Compare commits

...
14 Commits
Author SHA1 Message Date
bitdeals 58e3f22982 let the topology be pinned: trusted peer, outgoing switch, known nodes
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 1m50s
A private Bitmessage contour cannot be assembled by letting the nodes find
each other. The sybil check in connectionpool refuses a candidate whose /16 is
already among the outbound connections, and every container of a compose
project shares one /16 -- so each node keeps a single outbound connection to a
randomly chosen peer, and the contour splits into components on some runs and
not on others.

Three variables make the topology explicit instead:

  BITMESSAGE_TRUSTED_PEER    trustedpeer = host:port
  BITMESSAGE_SEND_OUTGOING   sendoutgoingconnections = True/False
  BITMESSAGE_KNOWN_NODES     host:port,... -> knownnodes.dat

With them a star is one line of config per node: the hub takes
SEND_OUTGOING=False and only accepts, the spokes take TRUSTED_PEER=<hub>:8444.

Details worth knowing:

- trustedpeer is absent from the stock keys.dat, so a substitution alone would
  be a silent no-op. The key is added the same way maxtotalconnections is,
  and it is added even when the value is empty -- that is how a node that was
  pinned before can be unpinned. Its anchors stop at "=" rather than "= ",
  because an empty value leaves no trailing space to match.
- knownnodes.dat is rewritten on every start, not only when missing. "Only
  when missing" would never have fired: the image ships one, built by the
  `pybitmessage -t` run in the Dockerfile, and a named volume inherits it.
  Seeding it is also what stops the DNS bootstrap -- deserialising any peer
  that is neither a DEFAULT_NODE nor "self" raises knownNodesActual, and
  startBootstrappers only runs while that flag is down.
- Both peer variables are validated here. PyBitmessage does check trustedpeer,
  but with a sys.exit() from a constructor in the network thread, which reads
  as a container that died for no stated reason.
2026-08-06 14:51:50 +00:00
bitdeals git user 2701c57200 cap total connections, and document the P2P port 8444
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 2m12s
The daemon has always listened on 8444 and nothing published it, so every
node built from this image was outbound-only. Publishing it is now a
documented choice rather than an omission -- including the two things that
are not obvious from the config: peers are told the port from `port` in
keys.dat rather than the one you mapped it to (so only 8444:8444 works),
and the node's own address is never configured at all, because every peer
replaces the hardcoded 127.0.0.1 in the version message with the IP it
sees on the socket.

An open port needs a brake, hence BITMESSAGE_MAXTOTALCONNECTIONS. It
defaults to the PyBitmessage stock 200, so nothing changes for existing
users of the image. The key is inserted when the stock config lacks it
instead of trusting the substitution: the PyBitmessage clone is unpinned,
and a silent no-op would ship a node that looks capped and is not.

The API port in the example compose moves to loopback, which is what the
README already prescribed.
2026-08-02 14:48:01 +00:00
bitdeals git user 335ee52c0d docs: Russian README, cross-linked, with the examples fixed
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 27s
Same pairing the bitdeals-ng repositories use: each file points at the
other under its first heading, and both examples are byte-identical across
the two so they cannot drift.

The examples were not safe to copy. They published the API on every
interface next to the default credentials it documents, carried no volume
-- so keys.dat, the node's Bitmessage identity, was lost on every image
update -- and the docker run one was missing a line continuation and did
not run at all. Ports are now on loopback, the volume is there, and the
run was checked verbatim on a host.

Also: stopresendingafterxdays is documented as 30, which is what run.sh
actually defaults to, not 60; the seed phrase is noted as regenerated per
start; and a short Notes section records what cost time to find out -- '%'
is unusable in the API password, clients have to percent-encode
credentials, and the health check waits for a network connection.
2026-08-02 13:52:05 +00:00
bitdeals git user a79d881647 escape the sed replacements, and stop the script failing silently
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 3m0s
The sed pass that configures the daemon punished anyone setting a strong
password: '&' in a replacement means the whole match, so a password
containing one was silently rewritten into something else, and the '|'
delimiter made sed exit with 'unknown option to s'. Every setting rode in
one invocation and the script had no set -e, so that failure applied none
of them -- not apipassword, not apienabled, not apiinterface -- and the
daemon came up on whatever it had before without saying so.

esc() now escapes backslash, '&' and the delimiter via printf. The
expressions are anchored to the start of the line and name their key in the
replacement instead of using \1, so no backreference is involved and
nothing in another section can match. keys.dat also holds privsigningkey
and privencryptionkey for this node's Bitmessage identities; editing in
place leaves every byte outside [bitmessagesettings] untouched, which is
why this stays a line edit rather than a parse-and-rewrite.

The clients needed the other half of this: credentials go into an XML-RPC
URL, where '@' splits the userinfo and '#' truncates the rest, so a strong
password wrote correctly and still failed to connect. Both now
percent-encode. A '%' in the password remains unusable -- it breaks
PyBitmessage's own config reader and every API call returns 500.

Also here, all found while making the above safe:
- set -eu, with the keys.dat chown guarded. A misconfiguration now stops
  the container instead of passing unnoticed.
- The seed-address retry loop used bash brace expansion under CMD ["sh"],
  where /bin/sh is dash and {1..4} is a literal, so it ran once, not four
  times.
- apt-get update shared a layer with nothing, letting a cached update feed
  install months-stale package lists.
- HEALTHCHECK gained a start period; the startup VACUUM takes tens of
  seconds on a large messages.dat and the container reported unhealthy for
  all of it.
- Removed the AppImage systemd unit, AppArmor profile and updater script.
  Nothing referenced them -- not the image, the deployment or the ansible
  roles -- and the updater fetched a binary with no signature or checksum
  check.
2026-08-02 13:13:56 +00:00
bitdeals git user 6641a452b5 raise SQL thread startup timeout to 600s
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 2m42s
The startup VACUUM of a large messages.dat exceeds the stock 60 s window,
and PyBitmessage then kills the daemon (os._exit). Since it dies mid-VACUUM
lastvacuumtime is never updated, so every later start repeats it and the
node stays down with its API not listening.
2026-08-02 10:46:10 +00:00
private-user a8c8861cad deterministic address fix
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 2m1s
2026-03-18 12:36:04 +03:00
private-user c957096762 add act_runner build job
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 28s
2026-03-18 11:42:32 +03:00
private-user ccac2e970a don't generate deterministic address by default 2026-03-18 11:36:27 +03:00
private-user 7761772dda add registry 2025-03-19 14:12:45 +03:00
private-user 28327d8604 add apivariant 2024-11-29 13:40:12 +03:00
private-user ed91f1ba49 add NOCACHE arg 2024-11-15 15:51:29 +03:00
private-user 1f6e63ddad dockerfile fix 2024-11-03 13:49:16 +03:00
private-user 6253ed1f5f Docker fix 2024-08-14 17:12:40 +03:00
private-user 9a88767eaf Docker fix 2024-08-14 17:08:57 +03:00
11 changed files with 496 additions and 226 deletions
+37
View File
@@ -0,0 +1,37 @@
name: Build docker image and push to registry.bitdeals.org
run-name: docker build and docker push
on:
push:
branches:
- main
- master
jobs:
main-build-job:
runs-on: ubuntu-latest
env:
VERSION: 1.0
COMMIT: ${{ gitea.sha }}
REPOSITORY: ${{ gitea.repository }}
#registry.bitdeals.org
REGISTRY: 10.0.3.111:5000
USER: ${{ secrets.DOCKER_USERNAME }}
PASS: ${{ secrets.DOCKER_PASSWORD }}
steps:
- name: Checkout repository code
uses: actions/checkout@v6
- name: Build docker app image
run: |
docker build . \
--file "$(find ./Dockerfile ./docker/Dockerfile -print -quit 2>/dev/null)" \
--label "git-commit=$COMMIT" \
--tag "${REGISTRY}/${REPOSITORY##*/}:${VERSION}.${COMMIT::7}" \
--tag "${REGISTRY}/${REPOSITORY##*/}:latest"
- name: Docker login
run: |
docker login --username "$USER" --password "$PASS" "$REGISTRY"
- name: Push images to registry
run: |
docker push "${REGISTRY}/${REPOSITORY##*/}:${VERSION}.${COMMIT::7}" ; \
docker push "${REGISTRY}/${REPOSITORY##*/}:latest"
+90 -16
View File
@@ -1,45 +1,67 @@
# Intro # Intro
> Русская версия: [README.ru-RU.md](README.ru-RU.md)
[PyBitmessage](https://bitmessage.org/) is a client of the Bitmessages P2P communication protocol used to send encrypted messages to another person or to many subscribers. [PyBitmessage](https://bitmessage.org/) is a client of the Bitmessages P2P communication protocol used to send encrypted messages to another person or to many subscribers.
PyBitmessage client running as a daemon in docker container with XML-RPC API enabled. PyBitmessage client running as a daemon in docker container with XML-RPC API enabled.
This repository covers the docker deployment only.
# Usage # Usage
The container generates a Bitmessage Deterministic Addresses based on a `BITMESSAGE_SEED_PHRASE` variable. The container generates a Bitmessage Deterministic Addresses based on a `BITMESSAGE_SEED_PHRASE` variable.
Here are some example snippets to help you get started creating a container. Here are some example snippets to help you get started creating a container.
The container has two ports and they are not interchangeable. **8442** is the
XML-RPC API: it controls the daemon completely and has no TLS, so set your own
credentials and keep it on loopback. **8444** is the Bitmessage P2P port:
publish it to let other nodes connect in, leave it unpublished to stay
outbound-only. The daemon listens on both inside the container either way.
## docker-compose ## docker-compose
```yaml ```yaml
version: "3"
services: services:
pybitmessage: pybitmessage:
image: bitdeals/pybitmessage build:
context: https://git.bitdeals.org/private/bitmessage.git
dockerfile: ./docker/Dockerfile
image: registry.bitdeals.org/bitmessage
environment: environment:
- BITMESSAGE_API_USER=bitmessage_api_user - BITMESSAGE_API_USER=CHANGE_ME
- BITMESSAGE_API_PASSWORD=bitmessage_api_password - BITMESSAGE_API_PASSWORD=CHANGE_ME
- BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase - BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase
- BITMESSAGE_SEED_ADDRESSES=1 - BITMESSAGE_SEED_ADDRESSES=1
- BITMESSAGE_TTL=172800 - BITMESSAGE_TTL=172800
- BITMESSAGE_STOPRESENDINGAFTERXDAYS=60 - BITMESSAGE_STOPRESENDINGAFTERXDAYS=60
- BITMESSAGE_MAXTOTALCONNECTIONS=40
ports: ports:
- 8442:8442 - 127.0.0.1:8442:8442 # API — loopback only
- 8444:8444 # P2P — omit this line to stay outbound-only
volumes:
- bitmessage:/home/bitmessage
volumes:
bitmessage:
``` ```
## docker cli ## docker cli
```sh ```sh
docker run -d \ docker run -d \
-e BITMESSAGE_API_USER=bitmessage_api_user \ -e BITMESSAGE_API_USER=CHANGE_ME \
-e BITMESSAGE_API_PASSWORD=bitmessage_api_password \ -e BITMESSAGE_API_PASSWORD=CHANGE_ME \
-e BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase \ -e BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase \
-e BITMESSAGE_SEED_ADDRESSES=1 \ -e BITMESSAGE_SEED_ADDRESSES=1 \
-e BITMESSAGE_TTL=172800 \ -e BITMESSAGE_TTL=172800 \
-e BITMESSAGE_STOPRESENDINGAFTERXDAYS=60 -e BITMESSAGE_STOPRESENDINGAFTERXDAYS=60 \
-p 8442:8442 \ -e BITMESSAGE_MAXTOTALCONNECTIONS=40 \
bitdeals/pybitmessage -p 127.0.0.1:8442:8442 \
-p 8444:8444 \
-v bitmessage:/home/bitmessage \
registry.bitdeals.org/bitmessage
``` ```
# Parameters # Parameters
@@ -48,11 +70,63 @@ Container images are configured using parameters passed at runtime.
|Parameter|Function| |Parameter|Function|
|:--------|:-------| |:--------|:-------|
|-p 8442|XML-RPC API port TCP| |-p 127.0.0.1:8442|API port. The daemon always binds `0.0.0.0` inside the container, so what you publish decides who reaches it|
|-e BITMESSAGE_API_USER=|XML-RPC API user. Default: `bitmessage_api_user`| |-p 8444|Bitmessage P2P port. Optional: without it the node still connects out to peers, it just cannot be connected to. Must be published as `8444:8444` — see Notes|
|-e BITMESSAGE_API_PASSWORD=|XML-RPC API password. Default: `bitmessage_api_password`| |-v /home/bitmessage|Data directory: `keys.dat` (identity, settings) and `messages.dat`. Without it the node is a new node after every update|
|-e BITMESSAGE_SEED_PHRASE|Create Deterministic Addresses password. Default: `bitmessage_seed_phrase`| |-e BITMESSAGE_API_USER|XML-RPC API user. Default: `bitmessage_api_user` — change it|
|-e BITMESSAGE_SEED_ADDRESSES|Number of Deterministic Addresses to generate. Default: `1`| |-e BITMESSAGE_API_PASSWORD|XML-RPC API password. Default: `bitmessage_api_password` — change it, see Notes|
|-e BITMESSAGE_SEED_PHRASE|Create Deterministic Addresses password. Default: regenerated on every start, giving different addresses each time. Only used when `BITMESSAGE_SEED_ADDRESSES` is above `0`|
|-e BITMESSAGE_SEED_ADDRESSES|Number of Deterministic Addresses to generate. Default: `0`|
|-e BITMESSAGE_TTL|The expiration of newly send messages, in seconds. Default: `172800`| |-e BITMESSAGE_TTL|The expiration of newly send messages, in seconds. Default: `172800`|
|-e BITMESSAGE_STOPRESENDINGAFTERXDAYS|Stop resending unreceived message after X days. Default: `60`| |-e BITMESSAGE_STOPRESENDINGAFTERXDAYS|Stop resending unreceived message after X days. Default: `30`|
|-e BITMESSAGE_APIVARIANT|provides xml or json-RPC API. Default: `legacy`|
|-e BITMESSAGE_MAXTOTALCONNECTIONS|Cap on all connections at once, inbound and outbound together (`maxoutboundconnections` is 8, so this minus 8 is the inbound headroom). Default: `200`, the PyBitmessage stock value — lower it when the P2P port is published|
|-e BITMESSAGE_TRUSTED_PEER|`host:port` of the one peer this node may connect out to; it dials nothing else. Default: empty — the node chooses its own peers. See Notes|
|-e BITMESSAGE_SEND_OUTGOING|Whether the node dials out at all, `True` or `False`. Default: `True`. `False` gives a node that only accepts inbound connections — the hub of a private contour|
|-e BITMESSAGE_KNOWN_NODES|Comma-separated `host:port` list, written into `knownnodes.dat` on every start in place of whatever was there. Default: empty — the file is left as it is. Also switches the DNS bootstrap off, see Notes|
# Notes
- `%` cannot be used in the API password: it breaks PyBitmessage's own config
reader, and every API call then returns `500` while `keys.dat` looks correct.
Other characters are fine, the container escapes them.
- Clients must percent-encode the credentials — they go into
`http://user:password@host:port/`, where `@`, `#`, `/` and `:` change how the
URL parses. The scripts in this image do; yours has to as well.
- The container turns healthy once the daemon has a network connection, which
on a new node takes a few minutes. The start period also covers the startup
`VACUUM` of `messages.dat`.
- **The P2P port must be published as `8444:8444`.** The daemon tells peers the
port from its own config (`port` in `keys.dat`), not the port you mapped it
to, so `8555:8444` advertises a port nobody can reach. A different host port
needs `extport` in `keys.dat`, which this container does not template.
- **Your own address is never configured.** The version message carries a
hardcoded `127.0.0.1` that every peer discards in favour of the IP it sees on
the socket, and it takes the port from that same message. So a node with 8444
published is found by the network on its own, as soon as it connects out —
there is no host IP or DNS name to set anywhere. The one exception is a Tor
hidden service, which needs an explicit `onionhostname`.
- **A private contour needs its peers pinned, and a star to pin them into.**
PyBitmessage refuses a candidate whose network group (the /16 for IPv4) is
already represented among its outbound connections. Every container of one
compose project lives in a single /16, so each node keeps exactly one outbound
connection, to a peer it picked at random — which as often as not leaves the
contour split into components. Give one node `BITMESSAGE_SEND_OUTGOING=False`
so it becomes a hub that only accepts (the check looks at outbound connections
only, so inbound are not capped by it), point the rest at it with
`BITMESSAGE_TRUSTED_PEER=<hub-ip>:8444`, and objects travel spoke → hub →
spokes. Use IP addresses, not service names: the sybil check parses the host
as an IP, and the `addr` exchange between nodes carries IPs anyway.
- **`BITMESSAGE_KNOWN_NODES` is what keeps a private contour private.** A node
whose `knownnodes.dat` names a peer outside PyBitmessage's built-in default
list stops asking `bootstrap8080.bitmessage.org` for more; without it even a
pinned node resolves the public bootstrap host on every start. The file is
rewritten on each start, so the variable, not the container's history, is what
the node believes on boot.
- **Publishing 8444 is a deliberate security trade-off.** The daemon runs on
Python 2 and already parses untrusted data from its outbound peers, so an open
port does not create that exposure — it changes *who* may connect, *when*, and
*how many*. The pre-handshake parser becomes reachable by anyone, and the
practical risk is resource exhaustion rather than code execution. Keep
`BITMESSAGE_MAXTOTALCONNECTIONS` low and put memory and CPU limits on the
container.
+133
View File
@@ -0,0 +1,133 @@
# Общие сведения
> English version: [README.md](README.md)
[PyBitmessage](https://bitmessage.org/) — клиент P2P-протокола обмена сообщениями Bitmessage, служащий для отправки шифрованных сообщений как одному адресату, так и множеству подписчиков.
Клиент PyBitmessage, работающий демоном в docker-контейнере с включённым XML-RPC API.
Репозиторий описывает только развёртывание в docker.
# Использование
Контейнер создаёт детерминированные адреса Bitmessage на основе переменной `BITMESSAGE_SEED_PHRASE`.
Ниже — примеры, с которых удобно начать создание контейнера.
У контейнера два порта, и они не взаимозаменяемы. **8442** — XML-RPC API: он
полностью управляет демоном и не имеет TLS, поэтому задайте свои учётные данные
и оставьте его на loopback. **8444** — P2P-порт Bitmessage: опубликуйте его,
чтобы к узлу могли подключаться другие, или не публикуйте, и тогда узел работает
только на исходящих. Внутри контейнера демон слушает оба в любом случае.
## docker-compose
```yaml
services:
pybitmessage:
build:
context: https://git.bitdeals.org/private/bitmessage.git
dockerfile: ./docker/Dockerfile
image: registry.bitdeals.org/bitmessage
environment:
- BITMESSAGE_API_USER=CHANGE_ME
- BITMESSAGE_API_PASSWORD=CHANGE_ME
- BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase
- BITMESSAGE_SEED_ADDRESSES=1
- BITMESSAGE_TTL=172800
- BITMESSAGE_STOPRESENDINGAFTERXDAYS=60
- BITMESSAGE_MAXTOTALCONNECTIONS=40
ports:
- 127.0.0.1:8442:8442 # API — только loopback
- 8444:8444 # P2P — уберите строку, чтобы остаться на исходящих
volumes:
- bitmessage:/home/bitmessage
volumes:
bitmessage:
```
## docker cli
```sh
docker run -d \
-e BITMESSAGE_API_USER=CHANGE_ME \
-e BITMESSAGE_API_PASSWORD=CHANGE_ME \
-e BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase \
-e BITMESSAGE_SEED_ADDRESSES=1 \
-e BITMESSAGE_TTL=172800 \
-e BITMESSAGE_STOPRESENDINGAFTERXDAYS=60 \
-e BITMESSAGE_MAXTOTALCONNECTIONS=40 \
-p 127.0.0.1:8442:8442 \
-p 8444:8444 \
-v bitmessage:/home/bitmessage \
registry.bitdeals.org/bitmessage
```
# Параметры
Образы контейнера настраиваются параметрами, передаваемыми при запуске.
|Параметр|Назначение|
|:--------|:-------|
|-p 127.0.0.1:8442|Порт API. Внутри контейнера демон всегда слушает `0.0.0.0`, поэтому доступность определяет то, что опубликовано|
|-p 8444|P2P-порт Bitmessage. Необязательный: без него узел всё равно подключается к пирам сам, просто к нему подключиться нельзя. Публиковать только как `8444:8444` — см. «Замечания»|
|-v /home/bitmessage|Каталог данных: `keys.dat` (личность, настройки) и `messages.dat`. Без него после каждого обновления это новый узел|
|-e BITMESSAGE_API_USER|Пользователь XML-RPC API. По умолчанию: `bitmessage_api_user` — измените|
|-e BITMESSAGE_API_PASSWORD|Пароль XML-RPC API. По умолчанию: `bitmessage_api_password` — измените, см. «Замечания»|
|-e BITMESSAGE_SEED_PHRASE|Парольная фраза для создания детерминированных адресов. По умолчанию: генерируется заново при каждом старте, то есть адреса каждый раз другие. Используется только при `BITMESSAGE_SEED_ADDRESSES` больше `0`|
|-e BITMESSAGE_SEED_ADDRESSES|Количество создаваемых детерминированных адресов. По умолчанию: `0`|
|-e BITMESSAGE_TTL|Срок жизни вновь отправляемых сообщений, в секундах. По умолчанию: `172800`|
|-e BITMESSAGE_STOPRESENDINGAFTERXDAYS|Прекратить повторную отправку недоставленного сообщения через X дней. По умолчанию: `30`|
|-e BITMESSAGE_APIVARIANT|Предоставляемый API: xml или json-RPC. По умолчанию: `legacy`|
|-e BITMESSAGE_MAXTOTALCONNECTIONS|Предел одновременных соединений, входящих и исходящих вместе (`maxoutboundconnections` равен 8, то есть это значение минус 8 — запас на входящие). По умолчанию: `200`, штатное значение PyBitmessage — снижайте, если P2P-порт опубликован|
|-e BITMESSAGE_TRUSTED_PEER|`host:port` единственного пира, к которому узел подключается наружу; больше ни к кому. По умолчанию: пусто — узел выбирает пиров сам. См. «Замечания»|
|-e BITMESSAGE_SEND_OUTGOING|Подключается ли узел наружу вообще: `True` или `False`. По умолчанию: `True`. При `False` получается узел, который только принимает входящие, — центр приватного контура|
|-e BITMESSAGE_KNOWN_NODES|Список `host:port` через запятую; записывается в `knownnodes.dat` при каждом старте вместо того, что там было. По умолчанию: пусто — файл не трогается. Заодно выключает бутстрап по DNS, см. «Замечания»|
# Замечания
- `%` в пароле API использовать нельзя: он ломает собственный чтец конфигурации
PyBitmessage, и любой вызов API отвечает `500`, притом что `keys.dat`
выглядит правильным. Остальные символы допустимы, контейнер их экранирует.
- Клиенты обязаны кодировать учётные данные — они попадают в
`http://user:password@host:port/`, где `@`, `#`, `/` и `:` меняют разбор URL.
Скрипты этого образа кодируют, ваш клиент должен тоже.
- Контейнер становится здоровым, когда у демона появилось сетевое соединение,
— на новом узле это несколько минут. Начальный период ожидания заодно
покрывает стартовый `VACUUM` файла `messages.dat`.
- **P2P-порт публикуется только как `8444:8444`.** Пирам демон сообщает порт из
собственной конфигурации (`port` в `keys.dat`), а не тот, в который вы его
отобразили, поэтому `8555:8444` объявляет сети порт, где никого нет. Для
другого порта на хосте нужен `extport` в `keys.dat`, а его этот контейнер не
подставляет.
- **Свой адрес нигде не указывается.** В version-сообщении демон шлёт
захардкоженный `127.0.0.1`, который каждый пир отбрасывает и берёт вместо него
IP, увиденный на сокете, а порт — из того же сообщения. Поэтому узел с
опубликованным 8444 сеть находит сама, как только он подключится наружу:
ни IP, ни DNS-имя хоста задавать негде. Единственное исключение — скрытый
сервис Tor, которому нужен явный `onionhostname`.
- **Приватному контуру нужны назначенные пиры и звезда, в которую их назначать.**
PyBitmessage отвергает кандидата, чья сетевая группа (для IPv4 — /16) уже
представлена среди его исходящих соединений. Все контейнеры одного
compose-проекта живут в одной /16, поэтому каждый узел удерживает ровно одно
исходящее соединение — со случайно выбранным пиром, и контур чаще всего
распадается на компоненты. Задайте одному узлу
`BITMESSAGE_SEND_OUTGOING=False`, и он станет хабом, который только принимает
(проверка смотрит лишь на исходящие, входящие она не ограничивает), остальные
направьте на него через `BITMESSAGE_TRUSTED_PEER=<ip-хаба>:8444` — объекты
пойдут спица → хаб → спицы. Адреса задавайте IP, а не именами сервисов:
проверка разбирает хост как IP, да и обмен `addr` между узлами оперирует IP.
- **`BITMESSAGE_KNOWN_NODES` — то, что делает приватный контур приватным.** Узел,
у которого в `knownnodes.dat` есть пир не из встроенного списка PyBitmessage,
перестаёт спрашивать адреса у `bootstrap8080.bitmessage.org`; без этого даже
узел с назначенным пиром при каждом старте резолвит публичный бутстрап-хост.
Файл переписывается на каждом старте, поэтому во что узел верит при загрузке,
определяет переменная, а не история контейнера.
- **Публикация 8444 — осознанный компромисс по безопасности.** Демон работает на
Python 2 и уже разбирает недоверенные данные от своих исходящих пиров, так что
открытый порт эту поверхность не создаёт — он меняет то, *кто* может
подключиться, *когда* и *сколько их*. Разбор до рукопожатия становится доступен
кому угодно, а реальный риск — исчерпание ресурсов, а не выполнение кода.
Держите `BITMESSAGE_MAXTOTALCONNECTIONS` низким и ограничьте контейнер по
памяти и CPU.
+13 -4
View File
@@ -1,16 +1,25 @@
services: services:
bitmessage: bitmessage:
image: bitdeals/pybitmessage:0.6.3.2-ubuntu build:
build: ./docker context: ./docker
dockerfile: Dockerfile
image: registry.bitdeals.org/bitmessage
environment: environment:
- BITMESSAGE_API_USER=bitmessage_api_user - BITMESSAGE_API_USER=bitmessage_api_user
- BITMESSAGE_API_PASSWORD=bitmessage_api_password - BITMESSAGE_API_PASSWORD=bitmessage_api_password
- BITMESSAGE_SEED_PHRASE=bitmessage_seed_phrase - BITMESSAGE_SEED_PHRASE=
- BITMESSAGE_SEED_ADDRESSES=1 - BITMESSAGE_SEED_ADDRESSES=1
- BITMESSAGE_TTL=172800 - BITMESSAGE_TTL=172800
- BITMESSAGE_STOPRESENDINGAFTERXDAYS=60 - BITMESSAGE_STOPRESENDINGAFTERXDAYS=60
- BITMESSAGE_MAXTOTALCONNECTIONS=40
ports: ports:
- 8442:8442 # The API controls the daemon completely and has no TLS, so it never
# leaves loopback -- the README has said so all along, this file did not.
- 127.0.0.1:8442:8442
# P2P. Only 8444:8444 works — the daemon announces its own configured
# port to peers, not the one you mapped it to. Drop this line to run
# outbound-only.
- 8444:8444
volumes: volumes:
- bitmessage:/home/bitmessage - bitmessage:/home/bitmessage
volumes: volumes:
+43 -10
View File
@@ -3,23 +3,53 @@ FROM ubuntu:bionic
SHELL ["/bin/bash", "-exo", "pipefail", "-c"] SHELL ["/bin/bash", "-exo", "pipefail", "-c"]
RUN apt-get update # Install dependencies. update and install share a layer on purpose: split
# across two, a cached update feeds install package lists that may be months
# Install dependencies # stale, and the install then fails or pulls something unintended.
RUN apt-get install -yq --no-install-suggests --no-install-recommends \ RUN apt-get update \
&& apt-get install -yq --no-install-suggests --no-install-recommends \
build-essential libcap-dev libssl-dev \ build-essential libcap-dev libssl-dev \
python-all-dev python-msgpack python-pip python-setuptools \ python-all-dev python-msgpack python-pip python-setuptools \
git git
## Do not use cache when building next layers of the image.
ARG NOCACHE=0
WORKDIR /root/PyBitmessage WORKDIR /root/PyBitmessage
RUN git clone https://github.com/Bitmessage/PyBitmessage . RUN git clone https://github.com/Bitmessage/PyBitmessage .
# Install # Install
RUN pip2 install jsonrpclib . RUN pip2 install jsonrpclib .
# Raise the SQL-thread startup timeout from the stock 60 s.
#
# PyBitmessage kills the daemon outright if the SQL thread is not ready within
# sql_timeout seconds (class_objectProcessor.py -> os._exit(1)). The startup
# VACUUM of a messages.dat that has grown to a few hundred MB does not fit in
# 60 s, and since the process dies mid-VACUUM lastvacuumtime is never updated,
# so every later start retries the same doomed VACUUM and the node never comes
# back. Measured: 26 s for a 264 MB database on an idle host, and the last
# start that did survive used 36 s of the 60.
#
# The greps are load-bearing: the clone above is unpinned, so if upstream ever
# moves or renames the constant, a silent no-op sed would ship an image that
# looks fixed and is not. Fail the build instead. The .pyc is refreshed because
# at runtime /usr/local is root-owned while the daemon runs as bitmessage, so a
# stale one can only be recompiled to memory on every start.
RUN f=/usr/local/lib/python2.7/dist-packages/pybitmessage/helper_sql.py \
&& grep -q '^sql_timeout = 60$' "$f" \
&& sed -i 's/^sql_timeout = 60$/sql_timeout = 600/' "$f" \
&& grep -q '^sql_timeout = 600$' "$f" \
&& rm -f "${f}c" \
&& python -c "import py_compile; py_compile.compile('$f')"
FROM ubuntu:bionic FROM ubuntu:bionic
EXPOSE 8442 # 8442 is the XML-RPC API (keep it on loopback), 8444 the Bitmessage P2P port.
# The daemon listens on both regardless; publishing 8444 is what makes the node
# reachable for inbound peers.
EXPOSE 8442/tcp
EXPOSE 8444/tcp
ENV USER_UID=2000 ENV USER_UID=2000
ENV USER_GID=2000 ENV USER_GID=2000
@@ -27,9 +57,9 @@ ENV HOME=/home/bitmessage
ENV BITMESSAGE_HOME=${HOME} ENV BITMESSAGE_HOME=${HOME}
COPY --from=0 /usr/local/ /usr/local/ COPY --from=0 /usr/local/ /usr/local/
COPY --from=0 /root/PyBitmessage/docker/healthy_check.py /usr/local/bin/ COPY ./docker/healthy_check.py /usr/local/bin/
COPY --from=0 /root/PyBitmessage/docker/seed_addr_gen.py /usr/local/bin/ COPY ./docker/seed_addr_gen.py /usr/local/bin/
COPY --from=0 /root/PyBitmessage/docker/run.sh /usr/local/bin/ COPY ./docker/run.sh /usr/local/bin/
# Install dependencies # Install dependencies
RUN apt-get update \ RUN apt-get update \
@@ -47,7 +77,10 @@ RUN su bitmessage -c "pybitmessage -t"
CMD ["sh", "/usr/local/bin/run.sh"] CMD ["sh", "/usr/local/bin/run.sh"]
## Check PyBitmessage active network connections ## Check PyBitmessage active network connections.
HEALTHCHECK --retries=0 --interval=15s \ ## The start period covers the startup VACUUM of messages.dat, which takes tens
## of seconds once the database reaches a few hundred MB; without it the
## container reports unhealthy for that whole window on every restart.
HEALTHCHECK --retries=0 --interval=15s --start-period=180s \
CMD ["python", "/usr/local/bin/healthy_check.py"] CMD ["python", "/usr/local/bin/healthy_check.py"]
+8 -1
View File
@@ -2,6 +2,7 @@
import sys import sys
import os import os
import urllib
import xmlrpclib import xmlrpclib
import json import json
@@ -9,7 +10,13 @@ api_user=os.getenv('BITMESSAGE_API_USER', 'bitmessage_api_user') ;
api_password=os.getenv('BITMESSAGE_API_PASSWORD', 'bitmessage_api_password') ; api_password=os.getenv('BITMESSAGE_API_PASSWORD', 'bitmessage_api_password') ;
api_port=os.getenv('BITMESSAGE_API_PORT', '8442') ; api_port=os.getenv('BITMESSAGE_API_PORT', '8442') ;
api_link="http://{}:{}@127.0.0.1:{}/".format(api_user, api_password, api_port) # Credentials go into a URL, so they must be percent-encoded: '@' splits the
# userinfo, '#' truncates the rest, '/' and ':' change what is parsed as host
# and port. Without this a strong password fails here while being perfectly
# valid in keys.dat. (A '%' in the password is a separate matter -- it breaks
# PyBitmessage's own config reader and makes every API call return 500.)
api_link="http://{}:{}@127.0.0.1:{}/".format(
urllib.quote(api_user, safe=''), urllib.quote(api_password, safe=''), api_port)
api = xmlrpclib.ServerProxy(api_link) api = xmlrpclib.ServerProxy(api_link)
+159 -29
View File
@@ -1,48 +1,178 @@
#!/bin/sh #!/bin/sh
export BITMESSAGE_API_USER=${BITMESSAGE_API_USER:-bitmessage_api_user} set -eu
export BITMESSAGE_API_PASSWORD=${BITMESSAGE_API_PASSWORD:-bitmessage_api_password}
export BITMESSAGE_SEED_ADDRESSES=${BITMESSAGE_SEED_ADDRESSES:-1}
export BITMESSAGE_API_PORT=${BITMESSAGE_API_PORT:-8442}
export BITMESSAGE_TTL=${BITMESSAGE_TTL:-172800}
export BITMESSAGE_STOPRESENDINGAFTERXDAYS=${BITMESSAGE_STOPRESENDINGAFTERXDAYS:-30}
SEED_FILE="address_seed.txt" export BITMESSAGE_API_USER="${BITMESSAGE_API_USER:-bitmessage_api_user}"
test -e "$SEED_FILE" || gosu bitmessage touch "$SEED_FILE" export BITMESSAGE_API_PASSWORD="${BITMESSAGE_API_PASSWORD:-bitmessage_api_password}"
export BITMESSAGE_SEED_ADDRESSES="${BITMESSAGE_SEED_ADDRESSES:-0}"
export BITMESSAGE_API_PORT="${BITMESSAGE_API_PORT:-8442}"
export BITMESSAGE_TTL="${BITMESSAGE_TTL:-172800}"
export BITMESSAGE_STOPRESENDINGAFTERXDAYS="${BITMESSAGE_STOPRESENDINGAFTERXDAYS:-30}"
export BITMESSAGE_APIVARIANT="${BITMESSAGE_APIVARIANT:-legacy}"
export BITMESSAGE_MAXTOTALCONNECTIONS="${BITMESSAGE_MAXTOTALCONNECTIONS:-200}"
export BITMESSAGE_TRUSTED_PEER="${BITMESSAGE_TRUSTED_PEER:-}"
export BITMESSAGE_SEND_OUTGOING="${BITMESSAGE_SEND_OUTGOING:-True}"
export BITMESSAGE_KNOWN_NODES="${BITMESSAGE_KNOWN_NODES:-}"
# Save seed to file, or use saved seed # Reject anything but a plain number: this value is written into keys.dat, and
if [ -n "$BITMESSAGE_SEED_PHRASE" ] # unlike the credentials below it has no business containing characters that
# esc() would have to neutralise. A typo here would otherwise land in the config
# as a key the daemon silently ignores.
case "$BITMESSAGE_MAXTOTALCONNECTIONS" in
'' | *[!0-9]*)
echo "BITMESSAGE_MAXTOTALCONNECTIONS must be a positive integer" >&2
exit 1
;;
esac
# sendoutgoingconnections is read with safeGetBoolean, which would take "yes" or
# "1" too; keys.dat is written by hand often enough that it is worth keeping one
# spelling in it. Anything else is a typo, and a typo here reads as False --
# a node that quietly never dials out.
case "$BITMESSAGE_SEND_OUTGOING" in
[Tt]rue) BITMESSAGE_SEND_OUTGOING=True ;;
[Ff]alse) BITMESSAGE_SEND_OUTGOING=False ;;
*)
echo "BITMESSAGE_SEND_OUTGOING must be True or False" >&2
exit 1
;;
esac
# host:port with a numeric port -- the form both consumers need. PyBitmessage
# does check trustedpeer itself, but by sys.exit() from a constructor deep in
# the network thread: the container dies with the reason buried in the daemon
# log. Fail here, where the message is the first thing in `docker logs`.
check_peer() {
case "$1" in
*:*) ;;
*) return 1 ;;
esac
[ -n "${1%:*}" ] || return 1
case "${1##*:}" in
'' | *[!0-9]*) return 1 ;;
esac
}
if [ -n "$BITMESSAGE_TRUSTED_PEER" ] && ! check_peer "$BITMESSAGE_TRUSTED_PEER"
then then
export BITMESSAGE_SEED_PHRASE echo "BITMESSAGE_TRUSTED_PEER must be host:port" >&2
grep -q "$BITMESSAGE_SEED_PHRASE" "$SEED_FILE" \ exit 1
|| echo "$BITMESSAGE_SEED_PHRASE" >> "$SEED_FILE"
else
OLD_SEED="$(tail -n1 $SEED_FILE)"
NEW_SEED="$(cat /dev/random | tr -dc "a-z" | head -c32)"
export BITMESSAGE_SEED_PHRASE="${OLD_SEED:-$NEW_SEED}"
fi fi
if [ -z "${BITMESSAGE_SEED_PHRASE:-}" ]
then
BITMESSAGE_SEED_PHRASE="$(cat /dev/random | tr -dc "a-z" | head -c32)"
export BITMESSAGE_SEED_PHRASE
fi
# Escape a value for use on the right-hand side of the sed expressions below.
# There, a backslash starts an escape, "&" stands for the whole match, and "|"
# ends the replacement because it is the delimiter. Unescaped, a password
# containing "&" was silently rewritten into something else and one containing
# "|" made sed fail outright.
esc() {
printf '%s' "$1" | sed -e 's/[\\&|]/\\&/g'
}
# this command must be run as root (for bind mounts to container) # this command must be run as root (for bind mounts to container)
if [ -f keys.dat ]
then
chown bitmessage:bitmessage keys.dat chown bitmessage:bitmessage keys.dat
chmod 600 keys.dat chmod 600 keys.dat
fi
# set config values # maxtotalconnections is the only brake on a node whose P2P port (8444) is
gosu bitmessage sed -i -e "s|\(apiinterface = \).*|\10\.0\.0\.0|g" \ # published: it caps inbound sockets at the total minus maxoutboundconnections.
-e "s|\(apivariant = \).*|\1legacy|g" \ # The substitution below is a no-op when the key is missing, which would ship a
-e "s|\(apiusername = \).*|\1$BITMESSAGE_API_USER|g" \ # node that looks capped and is not -- and the PyBitmessage clone in the
-e "s|\(apipassword = \).*|\1$BITMESSAGE_API_PASSWORD|g" \ # Dockerfile is unpinned, so the stock config is whatever upstream generates
-e "s|\(apiport = \).*|\1$BITMESSAGE_API_PORT|g" \ # today. Add the key rather than trust the substitution alone; line 1 is the
-e "s|\(apienabled = \).*|\1True|g" \ # [bitmessagesettings] header the daemon reads it from.
-e "s|\(ttl = \).*|\1$BITMESSAGE_TTL|g" \ if ! grep -q "^maxtotalconnections = " keys.dat
-e "s|\(stopresendingafterxdays = \).*|\1$BITMESSAGE_STOPRESENDINGAFTERXDAYS|g" \ then
-e "s|\(udp = \).*|\1False|g" keys.dat gosu bitmessage sed -i "1a maxtotalconnections = $BITMESSAGE_MAXTOTALCONNECTIONS" keys.dat
fi
# trustedpeer is absent from the stock keys.dat entirely, so the substitution
# below is a no-op until the key exists -- same trap as maxtotalconnections.
# The key is added even when the value is empty, which is how it can be taken
# back off a node that was pinned before: safeGet returns "" and connectionpool
# falls back to chooseConnection. That empty case is also why the anchors here
# stop at "=" instead of "= ": with nothing to the right there is no trailing
# space to match, and the substitution would never fire again.
if ! grep -q "^trustedpeer =" keys.dat
then
gosu bitmessage sed -i "1a trustedpeer = $(esc "$BITMESSAGE_TRUSTED_PEER")" keys.dat
fi
# Set config values. Every expression is anchored to the start of the line and
# names its key in the replacement, so no backreference is involved and nothing
# in another section can match. With set -e a failure here now stops the
# container instead of leaving the daemon on its previous settings unnoticed --
# including the case of a bind mount with no keys.dat at all.
gosu bitmessage sed -i \
-e "s|^apiinterface = .*|apiinterface = 0.0.0.0|" \
-e "s|^apivariant = .*|apivariant = $(esc "$BITMESSAGE_APIVARIANT")|" \
-e "s|^apiusername = .*|apiusername = $(esc "$BITMESSAGE_API_USER")|" \
-e "s|^apipassword = .*|apipassword = $(esc "$BITMESSAGE_API_PASSWORD")|" \
-e "s|^apiport = .*|apiport = $(esc "$BITMESSAGE_API_PORT")|" \
-e "s|^apienabled = .*|apienabled = True|" \
-e "s|^ttl = .*|ttl = $(esc "$BITMESSAGE_TTL")|" \
-e "s|^stopresendingafterxdays = .*|stopresendingafterxdays = $(esc "$BITMESSAGE_STOPRESENDINGAFTERXDAYS")|" \
-e "s|^maxtotalconnections = .*|maxtotalconnections = $BITMESSAGE_MAXTOTALCONNECTIONS|" \
-e "s|^trustedpeer =.*|trustedpeer = $(esc "$BITMESSAGE_TRUSTED_PEER")|" \
-e "s|^sendoutgoingconnections = .*|sendoutgoingconnections = $BITMESSAGE_SEND_OUTGOING|" \
-e "s|^udp = .*|udp = False|" keys.dat
# BITMESSAGE_KNOWN_NODES pins the peers the daemon starts from, and is rewritten
# on every start: in a private contour the seed *is* the topology, and a file
# left over from an earlier run names nodes that may no longer exist. Seeding it
# also switches off the DNS bootstrap -- json_deserialize_knownnodes raises
# knownNodesActual for any peer that is neither DEFAULT_NODES nor "self", and
# connectionpool calls startBootstrappers only while that flag is down, so the
# node never reaches bootstrap8080.bitmessage.org.
#
# Writing it "only when the file is missing" would have been a permanent no-op:
# the image ships a knownnodes.dat, produced by the `pybitmessage -t` run in the
# Dockerfile, and a named volume inherits it on first use.
if [ -n "$BITMESSAGE_KNOWN_NODES" ]
then
now="$(date +%s)"
nodes=""
oldifs="$IFS"
IFS=","
for peer in $BITMESSAGE_KNOWN_NODES
do
IFS="$oldifs"
if ! check_peer "$peer"
then
echo "BITMESSAGE_KNOWN_NODES entry '$peer' must be host:port" >&2
exit 1
fi
[ -z "$nodes" ] || nodes="$nodes,"
nodes="$nodes
{\"stream\": 1, \"peer\": {\"host\": \"${peer%:*}\", \"port\": ${peer##*:}},
\"info\": {\"lastseen\": $now, \"rating\": 0, \"self\": false}}"
IFS=","
done
IFS="$oldifs"
printf '[%s\n]\n' "$nodes" > knownnodes.dat
chown bitmessage:bitmessage knownnodes.dat
chmod 600 knownnodes.dat
fi
# generate address from seed # generate address from seed
for i in {1..4} if [ "$BITMESSAGE_SEED_ADDRESSES" -gt 0 ]
then
# Four attempts, not a bash {1..4}: this runs under dash, where brace
# expansion is literal and the loop would have run once. The call is
# idempotent (createDeterministicAddresses returns nothing for an address
# that already exists), so these are retries while the API comes up.
for i in 1 2 3 4
do do
sleep 15 sleep 15
gosu bitmessage /usr/bin/python /usr/local/bin/seed_addr_gen.py gosu bitmessage /usr/bin/python /usr/local/bin/seed_addr_gen.py
done & done &
fi
exec gosu bitmessage pybitmessage -d exec gosu bitmessage pybitmessage -d
+6 -2
View File
@@ -1,15 +1,19 @@
#!/usr/bin/python #!/usr/bin/python
import os import os
import urllib
import xmlrpclib import xmlrpclib
api_user=os.getenv('BITMESSAGE_API_USER', 'bitmessage_api_user') ; api_user=os.getenv('BITMESSAGE_API_USER', 'bitmessage_api_user') ;
api_password=os.getenv('BITMESSAGE_API_PASSWORD', 'bitmessage_api_password') ; api_password=os.getenv('BITMESSAGE_API_PASSWORD', 'bitmessage_api_password') ;
api_port=os.getenv('BITMESSAGE_API_PORT', '8442') ; api_port=os.getenv('BITMESSAGE_API_PORT', '8442') ;
addr_num=os.getenv('BITMESSAGE_SEED_ADDRESSES', '1') ; addr_num=os.getenv('BITMESSAGE_SEED_ADDRESSES', '0') ;
addr_seed=os.getenv('BITMESSAGE_SEED_PHRASE') ; addr_seed=os.getenv('BITMESSAGE_SEED_PHRASE') ;
api_link="http://{}:{}@127.0.0.1:{}/".format(api_user, api_password, api_port) # Percent-encode the credentials before they go into the URL -- see the same
# note in healthy_check.py.
api_link="http://{}:{}@127.0.0.1:{}/".format(
urllib.quote(api_user, safe=''), urllib.quote(api_password, safe=''), api_port)
api = xmlrpclib.ServerProxy(api_link) api = xmlrpclib.ServerProxy(api_link)
-94
View File
@@ -1,94 +0,0 @@
# Last Modified: Fri Oct 13 05:01:46 2023
include <tunables/global>
/**/PyBitmessage*.AppImage {
include <abstractions/apparmor_api/find_mountpoint>
include <abstractions/base>
include <abstractions/fonts>
include <abstractions/openssl>
include <abstractions/user-tmp>
capability dac_read_search,
capability sys_admin,
network inet dgram,
network inet stream,
network inet6 dgram,
network inet6 stream,
network netlink raw,
mount fstype=fuse.PyBitmessage*.AppImage options=(ro, nosuid, nodev),
umount,
/dev/fuse rw,
/etc/fuse.conf r,
/etc/gai.conf r,
/etc/host.conf r,
/etc/hosts r,
/etc/nsswitch.conf r,
/etc/python2.7/sitecustomize.py r,
/etc/resolv.conf r,
/etc/xdg/Trolltech.conf rk,
/proc/filesystems r,
/sys/devices/system/cpu/online r,
/tmp/*/*/.mount_PyBitm*/ r,
/tmp/*/*/.mount_PyBitm*/** r,
/tmp/*/*/.mount_PyBitm*/AppRun mrix,
/tmp/*/*/.mount_PyBitm*/lib/x86_64-linux-gnu/lib*.so* mr,
/tmp/*/*/.mount_PyBitm*/usr/bin/pybitmessage mrix,
/tmp/*/*/.mount_PyBitm*/usr/bin/qt.conf mrk,
/tmp/*/*/.mount_PyBitm*/usr/lib/python2.7/**.so mr,
/tmp/*/*/.mount_PyBitm*/usr/bin/python2.7 rix,
/tmp/*/*/.mount_PyBitm*/usr/lib/x86_64-linux-gnu/**/lib*.so* mr,
/tmp/*/*/.mount_PyBitm*/usr/lib/x86_64-linux-gnu/lib*.so* mr,
/tmp/*/*/.mount_PyBitm*/lib/x86_64/lib*.so mr,
/proc/*/cmdline r,
/usr/share/themes/** r,
owner /run/*/*/sni-qt_python2*/ rw,
owner /run/*/*/sni-qt_python2*/icons/ rw,
/tmp/.mount_PyBitm*/ r,
/tmp/.mount_PyBitm*/** r,
/tmp/.mount_PyBitm*/AppRun mrix,
/tmp/.mount_PyBitm*/lib/x86_64-linux-gnu/lib*.so* mr,
/tmp/.mount_PyBitm*/usr/bin/pybitmessage mrix,
/tmp/.mount_PyBitm*/usr/bin/qt.conf mrk,
/tmp/.mount_PyBitm*/usr/lib/python2.7/**.so mr,
/tmp/.mount_PyBitm*/usr/lib/x86_64-linux-gnu/**/lib*.so* mr,
/tmp/.mount_PyBitm*/usr/lib/x86_64-linux-gnu/lib*.so* mr,
/usr/bin/dash mrix,
/usr/bin/fusermount mrix,
/usr/bin/fusermount3 mrix,
/usr/bin/python2.7 r,
/usr/bin/stat mrix,
/usr/sbin/ldconfig mrix,
/usr/share/icons/ r,
/usr/share/icons/Adwaita/* r,
/usr/share/icons/Adwaita/** r,
/usr/share/icons/gnome/* r,
/usr/share/icons/hicolor/* rk,
/usr/share/mime/* r,
/usr/share/pixmaps/ r,
/usr/share/themes/Adwaita/** r,
owner /**/PyBitmessage*.AppImage mr,
owner /etc/passwd r,
owner @{HOME}/tmp* w,
owner /run/systemd/userdb/ r,
owner /run/*/*/sni-qt_python2_*/ rw,
owner /run/*/*/sni-qt_python2_*/icons/ rw,
owner /usr/local/share/fonts/** r,
owner @{HOME}/.cache/fontconfig/*-le64.cache-7 r,
owner @{HOME}/.config/PyBitmessage/ r,
owner @{HOME}/.config/PyBitmessage/debug.log w,
owner @{HOME}/.config/PyBitmessage/keys.dat rw,
owner @{HOME}/.config/PyBitmessage/keys.dat.*.bak w,
owner @{HOME}/.config/PyBitmessage/knownnodes.dat rw,
owner @{HOME}/.config/PyBitmessage/messages.dat rwk,
owner @{HOME}/.config/PyBitmessage/messages.dat-journal rw,
owner @{HOME}/.config/PyBitmessage/pybitmessageqt.conf rwk,
owner @{HOME}/.config/PyBitmessage/singleton.lock rwk,
owner @{HOME}/.config/Trolltech.conf rwk,
}
@@ -1,28 +0,0 @@
[Unit]
Description=Bitmessage appimage service
Documentation=https://bitmessage.org/wiki/API_Reference
ConditionPathExists=/home/bitmessage/PyBitmessage.AppImage
After=network.target
Wants=network.target
[Service]
Type=forking
ExecStart=/home/bitmessage/PyBitmessage.AppImage --daemon
WorkingDirectory=/home/bitmessage
PIDFile=/home/bitmessage/.config/PyBitmessage/singleton.lock
KillMode=process
Restart=always
RestartSec=10
#Nice=19
SyslogIdentifier=bitmessage
User=bitmessage
Group=bitmessage
PrivateTmp=yes
#ProtectHome=tmpfs
#BindPaths=/home/bitmessage/.config/PyBitmessage/
[Install]
WantedBy=multi-user.target
-35
View File
@@ -1,35 +0,0 @@
#!/bin/bash
#
#Be careful when downloading form https://artifacts.bitmessage.at. It's just a dump of binaries, it doesn't separate the official with development binaries.
#
#To find out which is the latest official one, go to github and click on the icon indicating the latest official build result.
#
#Peter Surda
#Bitmessage developer
#
set -ex
IMAGE_LIST="https://artifacts.bitmessage.at/appimage"
LAST_IMAGE="$(wget -q $IMAGE_LIST -O- | grep -oP '[[:digit:]]{5}' | tail -n1)"
IMAGE_FILENAME="$(wget -q $IMAGE_LIST/$LAST_IMAGE -O- | grep -oE '"PyBitmessage-.*-x86_64.AppImage"')"
IMAGE_FILENAME=${IMAGE_FILENAME:1:-1}
URL="$IMAGE_LIST/$LAST_IMAGE/$IMAGE_FILENAME"
DEST_FILE="$HOME/$IMAGE_FILENAME"
HARD_LINK="$HOME/PyBitmessage.AppImage"
if ! [ -f $DEST_FILE ]; then
wget -c $URL -O $DEST_FILE
chmod u+x $DEST_FILE
cp -v -fl $DEST_FILE $HARD_LINK
fi
#remove old appimage files
ls -1 -tc $HOME/PyBitmessage-.*-x86_64.AppImage 2>/dev/null \
| tail -n +3 \
| xargs -I{} rm -f $HOME/{}