Add tor v3 addresses support

pull/67/head
Christophe Mehay 5 years ago committed by Christophe Mehay
parent 8d562ed2e6
commit d3252e276e

1
.gitignore vendored

@ -105,3 +105,4 @@ ENV/
# more # more
key/ key/
.vscode

@ -1,5 +1,6 @@
repos:
- repo: git://github.com/pre-commit/pre-commit-hooks - repo: git://github.com/pre-commit/pre-commit-hooks
sha: v0.9.1 rev: v2.2.1
hooks: hooks:
- id: check-added-large-files - id: check-added-large-files
- id: check-docstring-first - id: check-docstring-first
@ -10,12 +11,14 @@
args: args:
- --exclude=__init__.py - --exclude=__init__.py
language_version: python3 language_version: python3
- id: autopep8-wrapper
language_version: python3
- id: requirements-txt-fixer - id: requirements-txt-fixer
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: 'v1.4.4'
hooks:
- id: autopep8
- repo: git://github.com/asottile/reorder_python_imports - repo: git://github.com/asottile/reorder_python_imports
sha: v0.3.5 rev: v1.4.0
hooks: hooks:
- id: reorder-python-imports - id: reorder-python-imports
language_version: python3 language_version: python3

@ -1,10 +1,10 @@
sudo: false sudo: false
dist: xenial
language: python language: python
python: python:
- "3.4" - '3.6'
- "3.5" - '3.7'
- "3.6"
install: pip install tox-travis pre-commit install: pip install tox-travis pre-commit
script: script:
- pre-commit run --all-files - pre-commit run --all-files
- tox - tox

@ -1,39 +1,43 @@
FROM alpine FROM alpine:latest
ARG tor_version
ENV HOME /var/lib/tor ENV HOME /var/lib/tor
RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils && \ RUN apk add --no-cache git libevent-dev openssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils zlib-dev && \
mkdir -p /usr/local/src/ && \ mkdir -p /usr/local/src/ && \
git clone https://git.torproject.org/tor.git /usr/local/src/tor && \ git clone https://git.torproject.org/tor.git /usr/local/src/tor && \
cd /usr/local/src/tor && \ cd /usr/local/src/tor && \
git checkout $(git branch -a | grep 'release' | sort -V | tail -1) && \ git checkout tor-$tor_version && \
./autogen.sh && \ ./autogen.sh && \
./configure \ ./configure \
--disable-asciidoc \ --disable-asciidoc \
--sysconfdir=/etc \ --sysconfdir=/etc \
--disable-unittests && \ --disable-unittests && \
make && make install && \ make && make install && \
cd .. && \ cd .. && \
rm -rf tor && \ rm -rf tor && \
apk add --no-cache python3 python3-dev && \ apk add --no-cache python3 python3-dev && \
python3 -m ensurepip && \ python3 -m ensurepip && \
rm -r /usr/lib/python*/ensurepip && \ rm -r /usr/lib/python*/ensurepip && \
pip3 install --upgrade pip setuptools pycrypto && \ pip3 install --upgrade pip setuptools && \
apk del git libevent-dev openssl-dev make automake python3-dev gcc autoconf musl-dev coreutils && \ apk del git libevent-dev openssl-dev make automake python3-dev autoconf musl-dev coreutils && \
apk add --no-cache libevent openssl apk add --no-cache libevent openssl
RUN mkdir -p /etc/tor/ RUN mkdir -p /etc/tor/
ADD assets/entrypoint-config.yml / COPY assets/onions /usr/local/src/onions
ADD assets/onions /usr/local/src/onions COPY assets/torrc /var/local/tor/torrc.tpl
ADD assets/torrc /var/local/tor/torrc.tpl
RUN cd /usr/local/src/onions && python3 setup.py install RUN cd /usr/local/src/onions && apk add --no-cache openssl-dev libffi-dev gcc python3-dev libc-dev && \
python3 setup.py install && \
apk del libffi-dev gcc python3-dev libc-dev openssl-dev
RUN mkdir -p ${HOME}/.tor && \ RUN mkdir -p ${HOME}/.tor && \
addgroup -S -g 107 tor && \ addgroup -S -g 107 tor && \
adduser -S -G tor -u 104 -H -h ${HOME} tor adduser -S -G tor -u 104 -H -h ${HOME} tor
COPY assets/entrypoint-config.yml /
VOLUME ["/var/lib/tor/hidden_service/"] VOLUME ["/var/lib/tor/hidden_service/"]

@ -1,23 +1,28 @@
.EXPORT_ALL_VARIABLES:
TOR_VERSION = $(shell bash last_tor_version.sh)
test: test:
tox tox
tag:
git tag v$(TOR_VERSION)
check: check:
pre-commit run --all-files pre-commit run --all-files
build: build:
docker-compose build - echo build with tor version $(TOR_VERSION)
docker-compose -f docker-compose.build.yml build
run: build rebuild:
docker-compose up docker-compose -f docker-compose.build.yml build --no-cache
build-v2: run: build
docker-compose -f docker-compose.v2.yml build docker-compose -f docker-compose-v1.yml up
run-v2: build-v2 run-v2: build
docker-compose -f docker-compose.v2.yml up docker-compose -f docker-compose.v2.yml up
build-v3: run-v3: build
docker-compose -f docker-compose.v3.yml build
run-v3: build-v3
docker-compose -f docker-compose.v3.yml up docker-compose -f docker-compose.v3.yml up

@ -0,0 +1,15 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
tox = "*"
[dev-packages]
tox = "*"
pre-commit = "*"
ptpython = "*"
cryptography = "*"
pylint = "*"
autopep8 = "*"

415
Pipfile.lock generated

@ -0,0 +1,415 @@
{
"_meta": {
"hash": {
"sha256": "98040ea608cfb470b37bd65b2b0092dc483e9d7781b613c1f526285eb992d3a0"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"filelock": {
"hashes": [
"sha256:b8d5ca5ca1c815e1574aee746650ea7301de63d87935b3463d26368b76e31633",
"sha256:d610c1bb404daf85976d7a82eb2ada120f04671007266b708606565dd03b5be6"
],
"version": "==3.0.10"
},
"pluggy": {
"hashes": [
"sha256:19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f",
"sha256:84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"
],
"version": "==0.9.0"
},
"py": {
"hashes": [
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
],
"version": "==1.8.0"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"toml": {
"hashes": [
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
],
"version": "==0.10.0"
},
"tox": {
"hashes": [
"sha256:69620e19de33a6b7ee8aeda5478791b3618ff58f0b869dbd0319fb71aa903deb",
"sha256:e5cdb1653aa27b3e46b5c390de6b6d51d31afcfdbd9d1222d82d76b82ad03d9b"
],
"index": "pypi",
"version": "==3.8.6"
},
"virtualenv": {
"hashes": [
"sha256:6aebaf4dd2568a0094225ebbca987859e369e3e5c22dc7d52e5406d504890417",
"sha256:984d7e607b0a5d1329425dd8845bd971b957424b5ba664729fab51ab8c11bc39"
],
"version": "==16.4.3"
}
},
"develop": {
"asn1crypto": {
"hashes": [
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
"sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49"
],
"version": "==0.24.0"
},
"aspy.yaml": {
"hashes": [
"sha256:ae249074803e8b957c83fdd82a99160d0d6d26dff9ba81ba608b42eebd7d8cd3",
"sha256:c7390d79f58eb9157406966201abf26da0d56c07e0ff0deadc39c8f4dbc13482"
],
"version": "==1.2.0"
},
"astroid": {
"hashes": [
"sha256:6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4",
"sha256:b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"
],
"version": "==2.2.5"
},
"autopep8": {
"hashes": [
"sha256:33d2b5325b7e1afb4240814fe982eea3a92ebea712869bfd08b3c0393404248c"
],
"index": "pypi",
"version": "==1.4.3"
},
"cffi": {
"hashes": [
"sha256:00b97afa72c233495560a0793cdc86c2571721b4271c0667addc83c417f3d90f",
"sha256:0ba1b0c90f2124459f6966a10c03794082a2f3985cd699d7d63c4a8dae113e11",
"sha256:0bffb69da295a4fc3349f2ec7cbe16b8ba057b0a593a92cbe8396e535244ee9d",
"sha256:21469a2b1082088d11ccd79dd84157ba42d940064abbfa59cf5f024c19cf4891",
"sha256:2e4812f7fa984bf1ab253a40f1f4391b604f7fc424a3e21f7de542a7f8f7aedf",
"sha256:2eac2cdd07b9049dd4e68449b90d3ef1adc7c759463af5beb53a84f1db62e36c",
"sha256:2f9089979d7456c74d21303c7851f158833d48fb265876923edcb2d0194104ed",
"sha256:3dd13feff00bddb0bd2d650cdb7338f815c1789a91a6f68fdc00e5c5ed40329b",
"sha256:4065c32b52f4b142f417af6f33a5024edc1336aa845b9d5a8d86071f6fcaac5a",
"sha256:51a4ba1256e9003a3acf508e3b4f4661bebd015b8180cc31849da222426ef585",
"sha256:59888faac06403767c0cf8cfb3f4a777b2939b1fbd9f729299b5384f097f05ea",
"sha256:59c87886640574d8b14910840327f5cd15954e26ed0bbd4e7cef95fa5aef218f",
"sha256:610fc7d6db6c56a244c2701575f6851461753c60f73f2de89c79bbf1cc807f33",
"sha256:70aeadeecb281ea901bf4230c6222af0248c41044d6f57401a614ea59d96d145",
"sha256:71e1296d5e66c59cd2c0f2d72dc476d42afe02aeddc833d8e05630a0551dad7a",
"sha256:8fc7a49b440ea752cfdf1d51a586fd08d395ff7a5d555dc69e84b1939f7ddee3",
"sha256:9b5c2afd2d6e3771d516045a6cfa11a8da9a60e3d128746a7fe9ab36dfe7221f",
"sha256:9c759051ebcb244d9d55ee791259ddd158188d15adee3c152502d3b69005e6bd",
"sha256:b4d1011fec5ec12aa7cc10c05a2f2f12dfa0adfe958e56ae38dc140614035804",
"sha256:b4f1d6332339ecc61275bebd1f7b674098a66fea11a00c84d1c58851e618dc0d",
"sha256:c030cda3dc8e62b814831faa4eb93dd9a46498af8cd1d5c178c2de856972fd92",
"sha256:c2e1f2012e56d61390c0e668c20c4fb0ae667c44d6f6a2eeea5d7148dcd3df9f",
"sha256:c37c77d6562074452120fc6c02ad86ec928f5710fbc435a181d69334b4de1d84",
"sha256:c8149780c60f8fd02752d0429246088c6c04e234b895c4a42e1ea9b4de8d27fb",
"sha256:cbeeef1dc3c4299bd746b774f019de9e4672f7cc666c777cd5b409f0b746dac7",
"sha256:e113878a446c6228669144ae8a56e268c91b7f1fafae927adc4879d9849e0ea7",
"sha256:e21162bf941b85c0cda08224dade5def9360f53b09f9f259adb85fc7dd0e7b35",
"sha256:fb6934ef4744becbda3143d30c6604718871495a5e36c408431bf33d9c146889"
],
"version": "==1.12.2"
},
"cfgv": {
"hashes": [
"sha256:6e9f2feea5e84bc71e56abd703140d7a2c250fc5ba38b8702fd6a68ed4e3b2ef",
"sha256:e7f186d4a36c099a9e20b04ac3108bd8bb9b9257e692ce18c8c3764d5cb12172"
],
"version": "==1.6.0"
},
"cryptography": {
"hashes": [
"sha256:066f815f1fe46020877c5983a7e747ae140f517f1b09030ec098503575265ce1",
"sha256:210210d9df0afba9e000636e97810117dc55b7157c903a55716bb73e3ae07705",
"sha256:26c821cbeb683facb966045e2064303029d572a87ee69ca5a1bf54bf55f93ca6",
"sha256:2afb83308dc5c5255149ff7d3fb9964f7c9ee3d59b603ec18ccf5b0a8852e2b1",
"sha256:2db34e5c45988f36f7a08a7ab2b69638994a8923853dec2d4af121f689c66dc8",
"sha256:409c4653e0f719fa78febcb71ac417076ae5e20160aec7270c91d009837b9151",
"sha256:45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d",
"sha256:48eab46ef38faf1031e58dfcc9c3e71756a1108f4c9c966150b605d4a1a7f659",
"sha256:6b9e0ae298ab20d371fc26e2129fd683cfc0cfde4d157c6341722de645146537",
"sha256:6c4778afe50f413707f604828c1ad1ff81fadf6c110cb669579dea7e2e98a75e",
"sha256:8c33fb99025d353c9520141f8bc989c2134a1f76bac6369cea060812f5b5c2bb",
"sha256:9873a1760a274b620a135054b756f9f218fa61ca030e42df31b409f0fb738b6c",
"sha256:9b069768c627f3f5623b1cbd3248c5e7e92aec62f4c98827059eed7053138cc9",
"sha256:9e4ce27a507e4886efbd3c32d120db5089b906979a4debf1d5939ec01b9dd6c5",
"sha256:acb424eaca214cb08735f1a744eceb97d014de6530c1ea23beb86d9c6f13c2ad",
"sha256:c8181c7d77388fe26ab8418bb088b1a1ef5fde058c6926790c8a0a3d94075a4a",
"sha256:d4afbb0840f489b60f5a580a41a1b9c3622e08ecb5eec8614d4fb4cd914c4460",
"sha256:d9ed28030797c00f4bc43c86bf819266c76a5ea61d006cd4078a93ebf7da6bfd",
"sha256:e603aa7bb52e4e8ed4119a58a03b60323918467ef209e6ff9db3ac382e5cf2c6"
],
"index": "pypi",
"version": "==2.6.1"
},
"docopt": {
"hashes": [
"sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"
],
"version": "==0.6.2"
},
"filelock": {
"hashes": [
"sha256:b8d5ca5ca1c815e1574aee746650ea7301de63d87935b3463d26368b76e31633",
"sha256:d610c1bb404daf85976d7a82eb2ada120f04671007266b708606565dd03b5be6"
],
"version": "==3.0.10"
},
"identify": {
"hashes": [
"sha256:244e7864ef59f0c7c50c6db73f58564151d91345cd9b76ed793458953578cadd",
"sha256:8ff062f90ad4b09cfe79b5dfb7a12e40f19d2e68a5c9598a49be45f16aba7171"
],
"version": "==1.4.1"
},
"importlib-metadata": {
"hashes": [
"sha256:46fc60c34b6ed7547e2a723fc8de6dc2e3a1173f8423246b3ce497f064e9c3de",
"sha256:bc136180e961875af88b1ab85b4009f4f1278f8396a60526c0009f503a1a96ca"
],
"version": "==0.9"
},
"isort": {
"hashes": [
"sha256:01cb7e1ca5e6c5b3f235f0385057f70558b70d2f00320208825fa62887292f43",
"sha256:268067462aed7eb2a1e237fcb287852f22077de3fb07964e87e00f829eea2d1a"
],
"version": "==4.3.17"
},
"jedi": {
"hashes": [
"sha256:2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b",
"sha256:2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"
],
"version": "==0.13.3"
},
"lazy-object-proxy": {
"hashes": [
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39",
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019",
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088",
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b",
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e",
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6",
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b",
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5",
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff",
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd",
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7",
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff",
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d",
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2",
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35",
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4",
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514",
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252",
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109",
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f",
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c",
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92",
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577",
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d",
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d",
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f",
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a",
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"
],
"version": "==1.3.1"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"nodeenv": {
"hashes": [
"sha256:ad8259494cf1c9034539f6cced78a1da4840a4b157e23640bc4a0c0546b0cb7a"
],
"version": "==1.3.3"
},
"parso": {
"hashes": [
"sha256:17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33",
"sha256:2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376"
],
"version": "==0.4.0"
},
"pluggy": {
"hashes": [
"sha256:19ecf9ce9db2fce065a7a0586e07cfb4ac8614fe96edf628a264b1c70116cf8f",
"sha256:84d306a647cc805219916e62aab89caa97a33a1dd8c342e87a37f91073cd4746"
],
"version": "==0.9.0"
},
"pre-commit": {
"hashes": [
"sha256:75a9110eae00d009c913616c0fc8a6a02e7716c4a29a14cac9b313d2c7338ab0",
"sha256:f882c65316eb5b705fe4613e92a7c91055c1800102e4d291cfd18912ec9cf90e"
],
"index": "pypi",
"version": "==1.15.1"
},
"prompt-toolkit": {
"hashes": [
"sha256:11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780",
"sha256:2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1",
"sha256:977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55"
],
"version": "==2.0.9"
},
"ptpython": {
"hashes": [
"sha256:51a74abe931f692360a32d650c2ba1ca329c08f3ed9b1de8abcd1164e0b0a6a7",
"sha256:938ee050e37d61c138dbbeb21383dfef8b9ed4ffb453a5f34041f42025bf5042",
"sha256:ebe9d68ea7532ec8ab306d4bdc7ec393701cd9bbd6eff0aa3067c821f99264d4"
],
"index": "pypi",
"version": "==2.0.4"
},
"py": {
"hashes": [
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
],
"version": "==1.8.0"
},
"pycodestyle": {
"hashes": [
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
],
"version": "==2.5.0"
},
"pycparser": {
"hashes": [
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
],
"version": "==2.19"
},
"pygments": {
"hashes": [
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
],
"version": "==2.3.1"
},
"pylint": {
"hashes": [
"sha256:5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09",
"sha256:723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1"
],
"index": "pypi",
"version": "==2.3.1"
},
"pyyaml": {
"hashes": [
"sha256:1adecc22f88d38052fb787d959f003811ca858b799590a5eaa70e63dca50308c",
"sha256:436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95",
"sha256:460a5a4248763f6f37ea225d19d5c205677d8d525f6a83357ca622ed541830c2",
"sha256:5a22a9c84653debfbf198d02fe592c176ea548cccce47553f35f466e15cf2fd4",
"sha256:7a5d3f26b89d688db27822343dfa25c599627bc92093e788956372285c6298ad",
"sha256:9372b04a02080752d9e6f990179a4ab840227c6e2ce15b95e1278456664cf2ba",
"sha256:a5dcbebee834eaddf3fa7366316b880ff4062e4bcc9787b78c7fbb4a26ff2dd1",
"sha256:aee5bab92a176e7cd034e57f46e9df9a9862a71f8f37cad167c6fc74c65f5b4e",
"sha256:c51f642898c0bacd335fc119da60baae0824f2cde95b0330b56c0553439f0673",
"sha256:c68ea4d3ba1705da1e0d85da6684ac657912679a649e8868bd850d2c299cce13",
"sha256:e23d0cc5299223dcc37885dae624f382297717e459ea24053709675a976a3e19"
],
"version": "==5.1"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"toml": {
"hashes": [
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
],
"version": "==0.10.0"
},
"tox": {
"hashes": [
"sha256:69620e19de33a6b7ee8aeda5478791b3618ff58f0b869dbd0319fb71aa903deb",
"sha256:e5cdb1653aa27b3e46b5c390de6b6d51d31afcfdbd9d1222d82d76b82ad03d9b"
],
"index": "pypi",
"version": "==3.8.6"
},
"typed-ast": {
"hashes": [
"sha256:035a54ede6ce1380599b2ce57844c6554666522e376bd111eb940fbc7c3dad23",
"sha256:037c35f2741ce3a9ac0d55abfcd119133cbd821fffa4461397718287092d9d15",
"sha256:049feae7e9f180b64efacbdc36b3af64a00393a47be22fa9cb6794e68d4e73d3",
"sha256:19228f7940beafc1ba21a6e8e070e0b0bfd1457902a3a81709762b8b9039b88d",
"sha256:2ea681e91e3550a30c2265d2916f40a5f5d89b59469a20f3bad7d07adee0f7a6",
"sha256:3a6b0a78af298d82323660df5497bcea0f0a4a25a0b003afd0ce5af049bd1f60",
"sha256:5385da8f3b801014504df0852bf83524599df890387a3c2b17b7caa3d78b1773",
"sha256:606d8afa07eef77280c2bf84335e24390055b478392e1975f96286d99d0cb424",
"sha256:69245b5b23bbf7fb242c9f8f08493e9ecd7711f063259aefffaeb90595d62287",
"sha256:6f6d839ab09830d59b7fa8fb6917023d8cb5498ee1f1dbd82d37db78eb76bc99",
"sha256:730888475f5ac0e37c1de4bd05eeb799fdb742697867f524dc8a4cd74bcecc23",
"sha256:9819b5162ffc121b9e334923c685b0d0826154e41dfe70b2ede2ce29034c71d8",
"sha256:9e60ef9426efab601dd9aa120e4ff560f4461cf8442e9c0a2b92548d52800699",
"sha256:af5fbdde0690c7da68e841d7fc2632345d570768ea7406a9434446d7b33b0ee1",
"sha256:b64efdbdf3bbb1377562c179f167f3bf301251411eb5ac77dec6b7d32bcda463",
"sha256:bac5f444c118aeb456fac1b0b5d14c6a71ea2a42069b09c176f75e9bd4c186f6",
"sha256:bda9068aafb73859491e13b99b682bd299c1b5fd50644d697533775828a28ee0",
"sha256:d659517ca116e6750101a1326107d3479028c5191f0ecee3c7203c50f5b915b0",
"sha256:eddd3fb1f3e0f82e5915a899285a39ee34ce18fd25d89582bc89fc9fb16cd2c6"
],
"markers": "implementation_name == 'cpython'",
"version": "==1.3.1"
},
"virtualenv": {
"hashes": [
"sha256:6aebaf4dd2568a0094225ebbca987859e369e3e5c22dc7d52e5406d504890417",
"sha256:984d7e607b0a5d1329425dd8845bd971b957424b5ba664729fab51ab8c11bc39"
],
"version": "==16.4.3"
},
"wcwidth": {
"hashes": [
"sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
"sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
],
"version": "==0.1.7"
},
"wrapt": {
"hashes": [
"sha256:4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533"
],
"version": "==1.11.1"
},
"zipp": {
"hashes": [
"sha256:55ca87266c38af6658b84db8cfb7343cdb0bf275f93c7afaea0d8e7a209c7478",
"sha256:682b3e1c62b7026afe24eadf6be579fb45fec54c07ea218bded8092af07a68c4"
],
"version": "==0.3.3"
}
}
}

@ -2,7 +2,161 @@
[![Build Status](https://travis-ci.org/cmehay/docker-tor-hidden-service.svg?branch=master)](https://travis-ci.org/cmehay/docker-tor-hidden-service) [![Build Status](https://travis-ci.org/cmehay/docker-tor-hidden-service.svg?branch=master)](https://travis-ci.org/cmehay/docker-tor-hidden-service)
Create a tor hidden service with a link ## Setup
### Setup hosts
From 2019, new conf to handle tor v3 address has been added. Here an example with `docker-compose` v2+:
```yaml
version: "2"
services:
tor:
image: goldy/tor-hidden-service:0.3.5.8
links:
- hello
- world
- again
environment:
# Set mapping ports
HELLO_TOR_SERVICE_HOSTS: 80:hello:80,800:hello:80,8888:hello:80
# Set private key
HELLO_TOR_SERVIVE_KEY: |
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C
NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH
dnFnHEcsllSEqD1hPAAvMUWwSMJaNmBEFtl8DUMS9tPX5fWGX4w5Xx8dZwIDAQAB
AoGBAMb20jMHxaZHWg2qTRYYJa8LdHgS0BZxkWYefnBUbZn7dOz7mM+tddpX6raK
8OSqyQu3Tc1tB9GjPLtnVr9KfVwhUVM7YXC/wOZo+u72bv9+4OMrEK/R8xy30XWj
GePXEu95yArE4NucYphxBLWMMu2E4RodjyJpczsl0Lohcn4BAkEA+XPaEKnNA3AL
1DXRpSpaa0ukGUY/zM7HNUFMW3UP00nxNCpWLSBmrQ56Suy7iSy91oa6HWkDD/4C
k0HslnMW5wJBANdz4ehByMJZmJu/b5y8wnFSqep2jmJ1InMvd18BfVoBTQJwGMAr
+qwSwNXXK2YYl9VJmCPCfgN0o7h1AEzvdYECQAM5UxUqDKNBvHVmqKn4zShb1ugY
t1RfS8XNbT41WhoB96MT9P8qTwlniX8UZiwUrvNp1Ffy9n4raz8Z+APNwvsCQQC9
AuaOsReEmMFu8VTjNh2G+TQjgvqKmaQtVNjuOgpUKYv7tYehH3P7/T+62dcy7CRX
cwbLaFbQhUUUD2DCHdkBAkB6CbB+qhu67oE4nnBCXllI9EXktXgFyXv/cScNvM9Y
FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ
-----END RSA PRIVATE KEY-----
# hello and again will share the same onion v3 address
FOO_TOR_SERVICE_HOSTS: 88:again:80,8000:world:80
FOO_TOR_SERVICE_VERSION: '3'
# tor v3 address private key base 64 encoded
FOO_TOR_SERVICE_KEY: |
PT0gZWQyNTUxOXYxLXNlY3JldDogdHlwZTAgPT0AAACArobDQYyZAWXei4QZwr++
j96H1X/gq14NwLRZ2O5DXuL0EzYKkdhZSILY85q+kfwZH8z4ceqe7u1F+0pQi/sM
hello:
image: tutum/hello-world
hostname: hello
world:
image: tutum/hello-world
hostname: world
again:
image: tutum/hello-world
hostname: again
```
This configuration will output:
```
foo: xwjtp3mj427zdp4tljiiivg2l5ijfvmt5lcsfaygtpp6cw254kykvpyd.onion:88, xwjtp3mj427zdp4tljiiivg2l5ijfvmt5lcsfaygtpp6cw254kykvpyd.onion:8000
hello: 5azvyr7dvvr4cldn.onion:80, 5azvyr7dvvr4cldn.onion:800, 5azvyr7dvvr4cldn.onion:8888
```
#### Environment variables
##### `{SERVICE}_TOR_SERVICE_HOSTS`
The config patern for this variable is: `{exposed_port}:{hostname}:{port}}`
For example `80:hello:8080` will expose a onion service on port 80 to the port 8080 of hello hostname.
You can concatenate services using comas.
##### `{SERVICE}_TOR_SERVICE_VERSION`
Can be `2` or `3`. Set the tor address type.
`2` gives short addresses `5azvyr7dvvr4cldn.onion` and `3` long addresses `xwjtp3mj427zdp4tljiiivg2l5ijfvmt5lcsfaygtpp6cw254kykvpyd.onion`
##### `{SERVICE}_TOR_SERVICE_KEY`
You can set the private key for the current service.
Tor v2 addresses uses RSA PEM keys like:
```
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C
NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH
dnFnHEcsllSEqD1hPAAvMUWwSMJaNmBEFtl8DUMS9tPX5fWGX4w5Xx8dZwIDAQAB
AoGBAMb20jMHxaZHWg2qTRYYJa8LdHgS0BZxkWYefnBUbZn7dOz7mM+tddpX6raK
8OSqyQu3Tc1tB9GjPLtnVr9KfVwhUVM7YXC/wOZo+u72bv9+4OMrEK/R8xy30XWj
GePXEu95yArE4NucYphxBLWMMu2E4RodjyJpczsl0Lohcn4BAkEA+XPaEKnNA3AL
1DXRpSpaa0ukGUY/zM7HNUFMW3UP00nxNCpWLSBmrQ56Suy7iSy91oa6HWkDD/4C
k0HslnMW5wJBANdz4ehByMJZmJu/b5y8wnFSqep2jmJ1InMvd18BfVoBTQJwGMAr
+qwSwNXXK2YYl9VJmCPCfgN0o7h1AEzvdYECQAM5UxUqDKNBvHVmqKn4zShb1ugY
t1RfS8XNbT41WhoB96MT9P8qTwlniX8UZiwUrvNp1Ffy9n4raz8Z+APNwvsCQQC9
AuaOsReEmMFu8VTjNh2G+TQjgvqKmaQtVNjuOgpUKYv7tYehH3P7/T+62dcy7CRX
cwbLaFbQhUUUD2DCHdkBAkB6CbB+qhu67oE4nnBCXllI9EXktXgFyXv/cScNvM9Y
FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ
-----END RSA PRIVATE KEY-----
```
Tor v3 addresses uses ed25519 binary keys. It should be base64 encoded:
```
PT0gZWQyNTUxOXYxLXNlY3JldDogdHlwZTAgPT0AAACArobDQYyZAWXei4QZwr++j96H1X/gq14NwLRZ2O5DXuL0EzYKkdhZSILY85q+kfwZH8z4ceqe7u1F+0pQi/sM
```
#### Secrets
Secret key can be set through docker `secrets`, see `docker-compose.v3.yml` for example.
### Tools
A command line tool `onions` is available in container to get `.onion` url when container is running.
```sh
# Get services
$ docker exec -ti torhiddenproxy_tor_1 onions
hello: vegm3d7q64gutl75.onion:80
world: b2sflntvdne63amj.onion:80
# Get json
$ docker exec -ti torhiddenproxy_tor_1 onions --json
{"hello": ["b2sflntvdne63amj.onion:80"], "world": ["vegm3d7q64gutl75.onion:80"]}
```
### Auto reload
Changing `/etc/tor/torrc` file triggers a `SIGHUP` signal to `tor` to reload configuration.
To disable this behavior, add `ENTRYPOINT_DISABLE_RELOAD` in environment.
### Versions
Container version will follow tor release versions.
### pyentrypoint
This container uses [`pyentrypoint`](https://github.com/cmehay/pyentrypoint) to generate its setup.
If you need to use the legacy version, please checkout the `legacy` branch or pull `goldy/tor-hidden-service:legacy`.
### pytor
This containner uses [`pytor`](https://github.com/cmehay/pytor) to mannages tor cryptography, generate keys and compute onion urls.
# Legacy deprecated doc
ALL THE DOC BELLOW IS LEGACY, IT'S STILL WORKING BUT IT'S NOT RECOMMENDED ANYMORE AND COULD BE DROPPED IN FUTURE RELEASES.
### Create a tor hidden service with a link
```sh ```sh
# run a container with a network application # run a container with a network application
@ -22,8 +176,6 @@ $ docker run -ti --link something --volume /path/to/keys:/var/lib/tor/hidden_ser
Look at the `docker-compose.yml` file to see how to use it. Look at the `docker-compose.yml` file to see how to use it.
## Setup
### Set private key ### Set private key
Private key is settable by environment or by copying file in `hostname/private_key` in docket volume (`hostname` is the link name). Private key is settable by environment or by copying file in `hostname/private_key` in docket volume (`hostname` is the link name).
@ -127,35 +279,3 @@ Links setting are required when using docker-compose v2. See `docker-compose.v2.
### Copose v3 support and secrets ### Copose v3 support and secrets
Links setting are required when using docker-compose v3. See `docker-compose.v3.yml` for example. Links setting are required when using docker-compose v3. See `docker-compose.v3.yml` for example.
#### Secrets
Secret key can be set through docker `secrets`, see `docker-compose.v3.yml` for example.
### Tools
A command line tool `onions` is available in container to get `.onion` url when container is running.
```sh
# Get services
$ docker exec -ti torhiddenproxy_tor_1 onions
hello: vegm3d7q64gutl75.onion:80
world: b2sflntvdne63amj.onion:80
# Get json
$ docker exec -ti torhiddenproxy_tor_1 onions --json
{"hello": ["b2sflntvdne63amj.onion:80"], "world": ["vegm3d7q64gutl75.onion:80"]}
```
### Auto reload
Changing `/etc/tor/torrc` file trigger a `SIGHUP` signal to `tor` to reload configuration.
To disable this behavior, add `ENTRYPOINT_DISABLE_RELOAD` in environment.
### pyentrypoint
This container is using [`pyentrypoint`](https://github.com/cmehay/pyentrypoint) to generate its setup.
If you need to use the legacy version, please checkout the `legacy` branch or pull `goldy/tor-hidden-service:legacy`.

@ -7,11 +7,13 @@ secret_env:
- '*_KEY' - '*_KEY'
- '*_PORTS' - '*_PORTS'
- '*_SERVICE_NAME' - '*_SERVICE_NAME'
- '*_TOR_SERVICE_*'
pre_conf_commands: pre_conf_commands:
- onions --setup-hosts - onions --setup-hosts
post_conf_commands: post_conf_commands:
- chmod -R 700 $HOME
- chown -R tor:tor $HOME - chown -R tor:tor $HOME
reload: reload:

@ -3,6 +3,7 @@ import argparse
import logging import logging
import os import os
import sys import sys
from base64 import b64decode
from json import dumps from json import dumps
from re import match from re import match
@ -46,6 +47,10 @@ class Setup(object):
assert len(key) > 800 assert len(key) > 800
self.setup[host]['key'] = key self.setup[host]['key'] = key
def _load_keys_in_services(self):
for service in self.services:
service.load_key()
def _get_service(self, host, service): def _get_service(self, host, service):
self._add_host(host) self._add_host(host)
self.setup[host]['service'] = service self.setup[host]['service'] = service
@ -66,30 +71,39 @@ class Setup(object):
if service: if service:
return service return service
def add_empty_group(self, name): def add_empty_group(self, name, version=None):
if self.find_group_by_name(name): if self.find_group_by_name(name):
raise Exception('Group {name} already exists'.format(name=name)) raise Exception('Group {name} already exists'.format(name=name))
group = ServicesGroup(name=name) group = ServicesGroup(name=name, version=version)
self.services.append(group) self.services.append(group)
return group return group
def add_new_service(self, host, name=None, ports=None, key=None): def add_new_service(self,
host,
name=None,
ports=None,
key=None):
group = self.find_group_by_name(name) group = self.find_group_by_name(name)
service = self.find_service_by_host(host) if group:
service = group.get_service_by_host(host)
else:
service = self.find_service_by_host(host)
if not service: if not service:
service = Service(host=host) service = Service(host=host)
if not group: if not group:
group = ServicesGroup( group = ServicesGroup(
service=service, service=service,
name=name, name=name,
hidden_service_dir=self.hidden_service_dir hidden_service_dir=self.hidden_service_dir,
) )
else: else:
group.add_service(service) group.add_service(service)
if group not in self.services: if group not in self.services:
self.services.append(group) self.services.append(group)
elif group and service not in group.services:
group.add_service(service)
else: else:
group = self.find_group_by_service(service) self.find_group_by_service(service)
if key: if key:
group.add_key(key) group.add_key(key)
if ports: if ports:
@ -108,22 +122,69 @@ class Setup(object):
self.add_new_service(host=host, ports=ports) self.add_new_service(host=host, ports=ports)
def _set_key(self, host, key): def _set_key(self, host, key):
self.add_new_service(host=host, key=key) self.add_new_service(host=host, key=key.encode())
def _setup_from_env(self): def _setup_from_env(self, match_map):
match_map = ( for reg, call in match_map:
(r'([A-Z0-9]*)_PORTS', self._set_ports), for key, val in os.environ.items():
(r'([A-Z0-9]*)_KEY', self._set_key),
)
for key, val in os.environ.items():
for reg, call in match_map:
m = match(reg, key) m = match(reg, key)
if m: if m:
call(m.groups()[0].lower(), val) call(m.groups()[0].lower(), val)
def _setup_keys_and_ports_from_env(self):
self._setup_from_env(
(
(r'([A-Z0-9]+)_PORTS', self._set_ports),
(r'([A-Z0-9]+)_KEY', self._set_key),
)
)
def get_or_create_empty_group(self, name, version=None):
group = self.find_group_by_name(name)
if group:
if version:
group.set_version(version)
return group
return self.add_empty_group(name, version)
def _set_group_version(self, name, version):
'Setup groups with version'
group = self.get_or_create_empty_group(name, version=version)
group.set_version(version)
def _set_group_key(self, name, key):
'Set key for service group'
group = self.get_or_create_empty_group(name)
if group.version == 3:
group.add_key(b64decode(key))
else:
group.add_key(key)
def _set_group_hosts(self, name, hosts):
'Set services for service groups'
self.get_or_create_empty_group(name)
for host_map in hosts.split(','):
host_map = host_map.strip()
port_from, host, port_dest = host_map.split(':', 2)
if host == 'unix' and port_dest.startswith('/'):
self.add_new_service(host=name, name=name, ports=host_map)
else:
ports = '{frm}:{dst}'.format(frm=port_from, dst=port_dest)
self.add_new_service(host=host, name=name, ports=ports)
def _setup_services_from_env(self):
self._setup_from_env(
(
(r'([A-Z0-9]+)_TOR_SERVICE_VERSION', self._set_group_version),
(r'([A-Z0-9]+)_TOR_SERVICE_KEY', self._set_group_key),
(r'([A-Z0-9]+)_TOR_SERVICE_HOSTS', self._set_group_hosts),
)
)
def _get_setup_from_env(self): def _get_setup_from_env(self):
self._set_service_names() self._set_service_names()
self._setup_from_env() self._setup_keys_and_ports_from_env()
self._setup_services_from_env()
def _get_setup_from_links(self): def _get_setup_from_links(self):
containers = DockerLinks().to_containers() containers = DockerLinks().to_containers()
@ -162,6 +223,7 @@ class Setup(object):
self.setup = {} self.setup = {}
self._get_setup_from_env() self._get_setup_from_env()
self._get_setup_from_links() self._get_setup_from_links()
self._load_keys_in_services()
self.check_services() self.check_services()
self.apply_conf() self.apply_conf()
@ -201,38 +263,65 @@ class Onions(Setup):
def torrc_parser(self): def torrc_parser(self):
self.torrc_dict = {}
def parse_dir(line): def parse_dir(line):
_, path = line.split() _, path = line.split()
group_name = os.path.basename(path) group_name = os.path.basename(path)
group = (self.find_group_by_name(group_name) self.torrc_dict[group_name] = {
or self.add_empty_group(group_name)) 'services': [],
return group }
return group_name
def parse_port(line, service_group): def parse_port(line, name):
_, port_from, dest = line.split() _, port_from, dest = line.split()
service_host, port = dest.split(':') service_host, port = dest.split(':')
ports_str = '{port_from}:{dest}' ports_str = '{port_from}:{dest}'
name = service_host
ports_param = ports_str.format(port_from=port_from, ports_param = ports_str.format(port_from=port_from,
dest=port) dest=port)
if port.startswith('/'): if port.startswith('/'):
name = service_group.name service_host = name
ports_param = ports_str.format(port_from=port_from, ports_param = ports_str.format(port_from=port_from,
dest=dest) dest=dest)
service = (service_group.get_service_by_host(name) self.torrc_dict[name]['services'].append({
or Service(name)) 'host': service_host,
service.add_ports(ports_param) 'ports': ports_param,
if service not in service_group.services: })
service_group.add_service(service)
def parse_version(line, name):
_, version = line.split()
self.torrc_dict[name]['version'] = int(version)
def setup_services():
for name, setup in self.torrc_dict.items():
version = setup.get('version', 2)
group = (self.find_group_by_name(name)
or self.add_empty_group(name, version=version))
for service_dict in setup.get('services', []):
host = service_dict['host']
service = (group.get_service_by_host(host)
or Service(host))
service.add_ports(service_dict['ports'])
if service not in group.services:
group.add_service(service)
self._load_keys_in_services()
if not os.path.exists(self.torrc): if not os.path.exists(self.torrc):
return return
with open(self.torrc, 'r') as f: try:
for line in f.readlines(): with open(self.torrc, 'r') as f:
if line.startswith('HiddenServiceDir'): for line in f.readlines():
service_group = parse_dir(line) if line.startswith('HiddenServiceDir'):
if line.startswith('HiddenServicePort'): name = parse_dir(line)
parse_port(line, service_group) if line.startswith('HiddenServicePort'):
parse_port(line, name)
if line.startswith('HiddenServiceVersion'):
parse_version(line, name)
except BaseException:
raise Exception(
'Fail to parse torrc file. Please check the file'
)
setup_services()
def __str__(self): def __str__(self):
if not self.services: if not self.services:
@ -257,6 +346,7 @@ def main():
help='Setup hosts') help='Setup hosts')
args = parser.parse_args() args = parser.parse_args()
logging.getLogger().setLevel(logging.WARNING)
try: try:
onions = Onions() onions = Onions()
if args.setup: if args.setup:
@ -264,6 +354,7 @@ def main():
else: else:
onions.torrc_parser() onions.torrc_parser()
except BaseException as e: except BaseException as e:
logging.exception(e)
error_msg = str(e) error_msg = str(e)
else: else:
error_msg = None error_msg = None
@ -271,7 +362,6 @@ def main():
if error_msg: if error_msg:
print(dumps({'error': error_msg})) print(dumps({'error': error_msg}))
sys.exit(1) sys.exit(1)
logging.getLogger().setLevel(logging.ERROR)
print(onions.to_json()) print(onions.to_json())
else: else:
if error_msg: if error_msg:

@ -1,42 +1,67 @@
'This class define a service link' 'This class define a service link'
import base64
import binascii
import logging import logging
import os import os
import pathlib
import re import re
from base64 import b32encode
from hashlib import sha1
from Crypto.PublicKey import RSA from pytor import OnionV2
from pytor import OnionV3
class ServicesGroup(object): class ServicesGroup(object):
name = None name = None
_priv_key = None version = None
_key_in_secrets = False imported_key = False
_default_version = 2
hidden_service_dir = "/var/lib/tor/hidden_service/" _imported_key = False
_onion = None
def __init__(self, name=None, service=None, hidden_service_dir=None): _hidden_service_dir = "/var/lib/tor/hidden_service/"
def __init__(self,
name=None,
service=None,
version=None,
hidden_service_dir=None):
name_regex = r'^[a-zA-Z0-9-_]+$' name_regex = r'^[a-zA-Z0-9-_]+$'
self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir self.onion_map = {
2: OnionV2,
3: OnionV3,
}
if not name and not service: if not name and not service:
raise Exception( raise Exception(
'Init service group with a name or service at least' 'Init service group with a name or service at least'
) )
self.services = [] self.services = []
self.name = name or service.host self.name = name or service.host
if hidden_service_dir:
self._hidden_service_dir = hidden_service_dir
if not re.match(name_regex, self.name): if not re.match(name_regex, self.name):
raise Exception( raise Exception(
'Group {name} has invalid name'.format(name=self.name) 'Group {name} has invalid name'.format(name=self.name)
) )
if service: if service:
self.add_service(service) self.add_service(service)
self.set_version(version or self._default_version)
self.gen_key()
def set_version(self, version):
version = int(version)
if version not in self.onion_map:
raise Exception(
'Url version {version} is not supported'.format(version)
)
self.version = version
self._onion = self.onion_map[version]()
self.load_key() @property
if not self._priv_key: def hidden_service_dir(self):
self.gen_key() return os.path.join(self._hidden_service_dir, self.name)
def add_service(self, service): def add_service(self, service):
if service not in self.services: if service not in self.services:
@ -50,15 +75,22 @@ class ServicesGroup(object):
return service return service
def add_key(self, key): def add_key(self, key):
if self._key_in_secrets: if self._imported_key:
logging.warning('Secret key already set, overriding') logging.warning('Secret key already set, overriding')
self._priv_key = key # Try to decode key from base64 encoding
self._key_in_secrets = False # import the raw data if the input cannot be decoded as base64
try:
key = base64.b64decode(key)
except binascii.Error:
pass
self._onion.set_private_key(key)
self._imported_key = True
def __iter__(self): def __iter__(self):
yield 'name', self.name yield 'name', self.name
yield 'onion', self.onion_url yield 'onion', self.onion_url
yield 'urls', list(self.urls) yield 'urls', list(self.urls)
yield 'version', self.version
def __str__(self): def __str__(self):
return '{name}: {urls}'.format(name=self.name, return '{name}: {urls}'.format(name=self.name,
@ -66,16 +98,7 @@ class ServicesGroup(object):
@property @property
def onion_url(self): def onion_url(self):
"Get onion url from private key" return self._onion.onion_hostname
# Convert private RSA to public DER
priv = RSA.importKey(self._priv_key.strip())
der = priv.publickey().exportKey("DER")
# hash key, keep first half of sha1, base32 encode
onion = b32encode(sha1(der[22:]).digest()[:10])
return '{onion}.onion'.format(onion=onion.decode().lower())
@property @property
def urls(self): def urls(self):
@ -88,30 +111,17 @@ class ServicesGroup(object):
'Write key on disk and set tor service' 'Write key on disk and set tor service'
if not hidden_service_dir: if not hidden_service_dir:
hidden_service_dir = self.hidden_service_dir hidden_service_dir = self.hidden_service_dir
serv_dir = os.path.join(hidden_service_dir, self.name) if not os.path.isdir(hidden_service_dir):
os.makedirs(serv_dir, exist_ok=True) pathlib.Path(hidden_service_dir).mkdir(parents=True)
os.chmod(serv_dir, 0o700) self._onion.write_hidden_service(hidden_service_dir, force=True)
with open(os.path.join(serv_dir, 'private_key'), 'w') as f:
f.write(self._priv_key)
os.fchmod(f.fileno(), 0o600)
with open(os.path.join(serv_dir, 'hostname'), 'w') as f:
f.write(self.onion_url)
def _load_key(self, key_file): def _load_key(self, key_file):
if os.path.exists(key_file): with open(key_file, 'rb') as f:
with open(key_file, 'r') as f: self._onion.set_private_key_from_file(f)
key = f.read().encode()
if not len(key): def load_key(self, override=False):
return if self._imported_key and not override:
try: return
rsa = RSA.importKey(key)
self._priv_key = rsa.exportKey("PEM").decode()
except BaseException:
raise('Fail to load key for {name} services'.format(
name=self.name
))
def load_key(self):
self.load_key_from_secrets() self.load_key_from_secrets()
self.load_key_from_conf() self.load_key_from_conf()
@ -122,8 +132,9 @@ class ServicesGroup(object):
return return
try: try:
self._load_key(secret_file) self._load_key(secret_file)
self._key_in_secrets = True self._imported_key = True
except BaseException: except BaseException as e:
logging.exception(e)
logging.warning('Fail to load key from secret, ' logging.warning('Fail to load key from secret, '
'check the key or secret name collision') 'check the key or secret name collision')
@ -131,16 +142,17 @@ class ServicesGroup(object):
'Load key from disk if exists' 'Load key from disk if exists'
if not hidden_service_dir: if not hidden_service_dir:
hidden_service_dir = self.hidden_service_dir hidden_service_dir = self.hidden_service_dir
key_file = os.path.join(hidden_service_dir, if not os.path.isdir(hidden_service_dir):
self.name, return
'private_key') self._onion.load_hidden_service(hidden_service_dir)
self._load_key(key_file)
def gen_key(self): def gen_key(self):
'Generate new 1024 bits RSA key for hidden service' self.imported_key = False
self._priv_key = RSA.generate( return self._onion.gen_new_private_key()
bits=1024,
).exportKey("PEM").decode() @property
def _priv_key(self):
return self._onion.get_private_key()
class Ports: class Ports:

@ -6,7 +6,7 @@ from setuptools import setup
setup( setup(
name='onions', name='onions',
version='0.4.1', version='0.5.0',
packages=find_packages(), packages=find_packages(),
@ -31,10 +31,9 @@ setup(
"Topic :: System :: Installation/Setup", "Topic :: System :: Installation/Setup",
], ],
install_requires=['pyentrypoint==0.5.1', install_requires=['pyentrypoint==0.5.2',
'Jinja2>=2.8', 'Jinja2>=2.10',
'pycrypto', ], 'pytor>=0.1.2'],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
'onions = onions:main', 'onions = onions:main',

@ -2,6 +2,7 @@ import json
import os import os
import re import re
from base64 import b32encode from base64 import b32encode
from base64 import b64decode
from hashlib import sha1 from hashlib import sha1
import pytest import pytest
@ -9,8 +10,9 @@ from Crypto.PublicKey import RSA
from onions import Onions from onions import Onions
def get_key_and_onion(): def get_key_and_onion(version=2):
key = ''' key = {}
key[2] = '''
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCsMP4gl6g1Q313miPhb1GnDr56ZxIWGsO2PwHM1infkbhlBakR MIICXAIBAAKBgQCsMP4gl6g1Q313miPhb1GnDr56ZxIWGsO2PwHM1infkbhlBakR
6DGQfpE31L1ZKTUxY0OexKbW088v8qCOfjD9Zk1i80JP4xzfWQcwFZ5yM/0fkhm3 6DGQfpE31L1ZKTUxY0OexKbW088v8qCOfjD9Zk1i80JP4xzfWQcwFZ5yM/0fkhm3
@ -27,24 +29,40 @@ La/7Syrnobngsh/vX90CQB+PSSBqiPSsK2yPz6Gsd6OLCQ9sdy2oRwFTasH8sZyl
bhJ3M9WzP/EMkAzyW8mVs1moFp3hRcfQlZHl6g1U9D8= bhJ3M9WzP/EMkAzyW8mVs1moFp3hRcfQlZHl6g1U9D8=
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
''' '''
onion = {}
onion = b32encode( pub = {}
onion[2] = b32encode(
sha1( sha1(
RSA.importKey( RSA.importKey(
key.strip() key[2].strip()
).publickey().exportKey( ).publickey().exportKey(
"DER" "DER"
)[22:] )[22:]
).digest()[:10] ).digest()[:10]
).decode().lower() + '.onion' ).decode().lower() + '.onion'
return key.strip(), onion key[3] = '''
PT0gZWQyNTUxOXYxLXNlY3JldDogdHlwZTAgPT0AAACArobDQYyZAWXei4QZwr++j96H1X/gq14N
wLRZ2O5DXuL0EzYKkdhZSILY85q+kfwZH8z4ceqe7u1F+0pQi/sM
'''
pub[3] = '''
PT0gZWQyNTUxOXYxLXB1YmxpYzogdHlwZTAgPT0AAAC9kzftiea/kb+TWlCEVNpfUJLVk+rFIoMG
m9/hW13isA==
'''
onion[3] = 'xwjtp3mj427zdp4tljiiivg2l5ijfvmt5lcsfaygtpp6cw254kykvpyd.onion'
return key[version].strip(), onion[version]
def get_torrc_template(): def get_torrc_template():
return r''' return r'''
{% for service_group in services %} {% for service_group in services %}
HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} HiddenServiceDir {{service_group.hidden_service_dir}}
{% if service_group.version == 3 %}
HiddenServiceVersion 3
{% endif %}
{% for service in service_group.services %} {% for service in service_group.services %}
{% for port in service.ports %} {% for port in service.ports %}
{% if port.is_socket %} {% if port.is_socket %}
@ -155,7 +173,7 @@ ff02::2 ip6-allrouters
172.17.0.2 compose_service1_1 bf447f22cdba 172.17.0.2 compose_service1_1 bf447f22cdba
'''.strip() '''.strip()
fs.CreateFile('/etc/hosts', contents=etc_host) fs.create_file('/etc/hosts', contents=etc_host)
monkeypatch.setattr(os, 'environ', env) monkeypatch.setattr(os, 'environ', env)
@ -190,34 +208,57 @@ def test_key(monkeypatch):
assert onion.services[0].onion_url == onion_url assert onion.services[0].onion_url == onion_url
def test_key_v3(monkeypatch):
key, onion_url = get_key_and_onion(version=3)
env = {
'GROUP1_TOR_SERVICE_HOSTS': '80:service1:80,81:service2:80',
'GROUP1_TOR_SERVICE_VERSION': '3',
'GROUP1_TOR_SERVICE_KEY': key,
}
monkeypatch.setattr(os, 'environ', env)
onion = Onions()
onion._get_setup_from_env()
onion._load_keys_in_services()
assert len(os.environ) == 3
assert len(onion.services) == 1
assert onion.services[0].onion_url == onion_url
def test_key_in_secret(fs, monkeypatch): def test_key_in_secret(fs, monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'GROUP1_TOR_SERVICE_HOSTS': '80:service1:80',
'SERVICE2_SERVICE_NAME': 'group1', 'GROUP2_TOR_SERVICE_HOSTS': '80:service2:80',
'SERVICE3_SERVICE_NAME': 'group2', 'GROUP3_TOR_SERVICE_HOSTS': '80:service3:80',
'SERVICE1_PORTS': '80:80', 'GROUP3_TOR_SERVICE_VERSION': '3',
'SERVICE2_PORTS': '81:80,82:8000',
'SERVICE3_PORTS': '80:unix://unix.socket',
} }
monkeypatch.setattr(os, 'environ', env) monkeypatch.setattr(os, 'environ', env)
key, onion_url = get_key_and_onion() key_v2, onion_url_v2 = get_key_and_onion()
key_v3, onion_url_v3 = get_key_and_onion(version=3)
fs.CreateFile('/run/secrets/group1', contents=key) fs.create_file('/run/secrets/group1', contents=key_v2)
fs.create_file('/run/secrets/group3', contents=b64decode(key_v3))
onion = Onions() onion = Onions()
onion._get_setup_from_env() onion._get_setup_from_env()
onion._load_keys_in_services()
group1 = onion.find_group_by_name('group1') group1 = onion.find_group_by_name('group1')
group2 = onion.find_group_by_name('group2') group2 = onion.find_group_by_name('group2')
group3 = onion.find_group_by_name('group3')
assert group1.onion_url == onion_url_v2
assert group2.onion_url not in [onion_url_v2, onion_url_v3]
assert group3.onion_url == onion_url_v3
# assert group._priv_key == key
assert group1.onion_url == onion_url
assert group2.onion_url != onion_url
def test_configuration(fs, monkeypatch, tmpdir):
def test_configuration(fs, monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'SERVICE1_SERVICE_NAME': 'group1',
'SERVICE2_SERVICE_NAME': 'group1', 'SERVICE2_SERVICE_NAME': 'group1',
@ -225,44 +266,72 @@ def test_configuration(fs, monkeypatch):
'SERVICE1_PORTS': '80:80', 'SERVICE1_PORTS': '80:80',
'SERVICE2_PORTS': '81:80,82:8000', 'SERVICE2_PORTS': '81:80,82:8000',
'SERVICE3_PORTS': '80:unix://unix.socket', 'SERVICE3_PORTS': '80:unix://unix.socket',
'GROUP3_TOR_SERVICE_VERSION': '2',
'GROUP3_TOR_SERVICE_HOSTS': '80:service4:888,81:service5:8080',
'GROUP4_TOR_SERVICE_VERSION': '3',
'GROUP4_TOR_SERVICE_HOSTS': '81:unix://unix2.sock',
'GROUP3V3_TOR_SERVICE_VERSION': '3',
'GROUP3V3_TOR_SERVICE_HOSTS': '80:service4:888,81:service5:8080',
'SERVICE5_TOR_SERVICE_HOSTS': '80:service5:80'
} }
hidden_dir = '/var/lib/tor/hidden_service'
monkeypatch.setattr(os, 'environ', env) monkeypatch.setattr(os, 'environ', env)
monkeypatch.setattr(os, 'fchmod', lambda x, y: None) monkeypatch.setattr(os, 'fchmod', lambda x, y: None)
key, onion_url = get_key_and_onion()
torrc_tpl = get_torrc_template() torrc_tpl = get_torrc_template()
fs.CreateFile('/var/local/tor/torrc.tpl', contents=torrc_tpl) fs.create_file('/var/local/tor/torrc.tpl', contents=torrc_tpl)
fs.CreateFile('/etc/tor/torrc') fs.create_file('/etc/tor/torrc')
fs.create_dir(hidden_dir)
onion = Onions() onion = Onions()
onion._get_setup_from_env() onion._get_setup_from_env()
onion._load_keys_in_services()
onion.apply_conf() onion.apply_conf()
onions_urls = {}
for dir in os.listdir(hidden_dir):
with open(os.path.join(hidden_dir, dir, 'hostname'), 'r') as f:
onions_urls[dir] = f.read().strip()
with open('/etc/tor/torrc', 'r') as f: with open('/etc/tor/torrc', 'r') as f:
torrc = f.read() torrc = f.read()
print(torrc)
assert 'HiddenServiceDir /var/lib/tor/hidden_service/group1' in torrc assert 'HiddenServiceDir /var/lib/tor/hidden_service/group1' in torrc
assert 'HiddenServicePort 80 service1:80' in torrc assert 'HiddenServicePort 80 service1:80' in torrc
assert 'HiddenServicePort 81 service2:80' in torrc assert 'HiddenServicePort 81 service2:80' in torrc
assert 'HiddenServicePort 82 service2:8000' in torrc assert 'HiddenServicePort 82 service2:8000' in torrc
assert 'HiddenServiceDir /var/lib/tor/hidden_service/group2' in torrc assert 'HiddenServiceDir /var/lib/tor/hidden_service/group2' in torrc
assert 'HiddenServicePort 80 unix://unix.socket' in torrc assert 'HiddenServicePort 80 unix://unix.socket' in torrc
assert 'HiddenServiceDir /var/lib/tor/hidden_service/group3' in torrc
assert 'HiddenServiceDir /var/lib/tor/hidden_service/group4' in torrc
assert 'HiddenServiceDir /var/lib/tor/hidden_service/group3v3' in torrc
assert 'HiddenServiceDir /var/lib/tor/hidden_service/service5' in torrc
assert torrc.count('HiddenServicePort 80 service4:888') == 2
assert torrc.count('HiddenServicePort 81 service5:8080') == 2
assert torrc.count('HiddenServicePort 80 service5:80') == 1
assert torrc.count('HiddenServicePort 81 unix://unix2.sock') == 1
assert torrc.count('HiddenServiceVersion 3') == 2
# Check parser # Check parser
onion2 = Onions() onion2 = Onions()
onion2.torrc_parser() onion2.torrc_parser()
assert len(onion2.services) == 2 assert len(onion2.services) == 6
assert set( assert set(
group.name for group in onion2.services group.name for group in onion2.services
) == set(['group1', 'group2']) # ) == set(['group1', 'group2'])
) == set(['group1', 'group2', 'group3', 'group4', 'group3v3', 'service5'])
for group in onion2.services: for group in onion2.services:
if group.name == 'group1': if group.name == 'group1':
assert len(group.services) == 2 assert len(group.services) == 2
assert group.version == 2
assert group.onion_url == onions_urls[group.name]
assert set( assert set(
service.host for service in group.services service.host for service in group.services
) == set(['service1', 'service2']) ) == set(['service1', 'service2'])
@ -279,6 +348,8 @@ def test_configuration(fs, monkeypatch):
) == set([(81, 80), (82, 8000)]) ) == set([(81, 80), (82, 8000)])
if group.name == 'group2': if group.name == 'group2':
assert len(group.services) == 1 assert len(group.services) == 1
assert group.version == 2
assert group.onion_url == onions_urls[group.name]
assert set( assert set(
service.host for service in group.services service.host for service in group.services
) == set(['group2']) ) == set(['group2'])
@ -288,6 +359,53 @@ def test_configuration(fs, monkeypatch):
(port.port_from, port.dest) for port in service.ports (port.port_from, port.dest) for port in service.ports
) == set([(80, 'unix://unix.socket')]) ) == set([(80, 'unix://unix.socket')])
if group.name in ['group3', 'group3v3']:
assert len(group.services) == 2
assert group.version == 2 if group.name == 'group3' else 3
assert group.onion_url == onions_urls[group.name]
assert set(
service.host for service in group.services
) == set(['service4', 'service5'])
for service in group.services:
if service.host == 'service4':
assert len(service.ports) == 1
assert set(
(port.port_from, port.dest) for port in service.ports
) == set([(80, 888)])
if service.host == 'service5':
assert len(service.ports) == 1
assert set(
(port.port_from, port.dest) for port in service.ports
) == set([(81, 8080)])
if group.name == 'group4':
assert len(group.services) == 1
assert group.version == 3
assert group.onion_url == onions_urls[group.name]
assert set(
service.host for service in group.services
) == set(['group4'])
for service in group.services:
assert service.host == 'group4'
assert len(service.ports) == 1
assert set(
(port.port_from, port.dest) for port in service.ports
) == set([(81, 'unix://unix2.sock')])
if group.name == 'service5':
assert len(group.services) == 1
assert group.version == 2
assert group.onion_url == onions_urls[group.name]
assert set(
service.host for service in group.services
) == set(['service5'])
for service in group.services:
assert service.host == 'service5'
assert len(service.ports) == 1
assert set(
(port.port_from, port.dest) for port in service.ports
) == set([(80, 80)])
def test_groups(monkeypatch): def test_groups(monkeypatch):
env = { env = {

@ -1,5 +1,8 @@
{% for service_group in services %} {% for service_group in services %}
HiddenServiceDir /var/lib/tor/hidden_service/{{service_group.name}} HiddenServiceDir {{service_group.hidden_service_dir}}
{% if service_group.version == 3 %}
HiddenServiceVersion 3
{% endif %}
{% for service in service_group.services %} {% for service in service_group.services %}
{% for port in service.ports %} {% for port in service.ports %}
{% if port.is_socket %} {% if port.is_socket %}

@ -0,0 +1,11 @@
# docker version 3 builder
version: "3.1"
services:
tor:
image: goldy/tor-hidden-service:$TOR_VERSION
build:
context: .
args:
tor_version: $TOR_VERSION

@ -1,7 +1,9 @@
# docker-compose.yml example # docker-compose.yml example
# LEGACY CONFIGURATION
# SEE README FOR INFORMATIONS
tor: tor:
image: goldy/tor-hidden-service image: goldy/tor-hidden-service:$TOR_VERSION
links: links:
- hello - hello
- world - world

@ -0,0 +1,59 @@
# docker version 2 example
version: "2"
services:
tor:
image: goldy/tor-hidden-service:$TOR_VERSION
links:
- hello
- world
- again
environment:
# Set mapping ports
HELLO_PORTS: 80:80,800:80,8888:80
# Set private key
HELLO_KEY: |
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C
NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH
dnFnHEcsllSEqD1hPAAvMUWwSMJaNmBEFtl8DUMS9tPX5fWGX4w5Xx8dZwIDAQAB
AoGBAMb20jMHxaZHWg2qTRYYJa8LdHgS0BZxkWYefnBUbZn7dOz7mM+tddpX6raK
8OSqyQu3Tc1tB9GjPLtnVr9KfVwhUVM7YXC/wOZo+u72bv9+4OMrEK/R8xy30XWj
GePXEu95yArE4NucYphxBLWMMu2E4RodjyJpczsl0Lohcn4BAkEA+XPaEKnNA3AL
1DXRpSpaa0ukGUY/zM7HNUFMW3UP00nxNCpWLSBmrQ56Suy7iSy91oa6HWkDD/4C
k0HslnMW5wJBANdz4ehByMJZmJu/b5y8wnFSqep2jmJ1InMvd18BfVoBTQJwGMAr
+qwSwNXXK2YYl9VJmCPCfgN0o7h1AEzvdYECQAM5UxUqDKNBvHVmqKn4zShb1ugY
t1RfS8XNbT41WhoB96MT9P8qTwlniX8UZiwUrvNp1Ffy9n4raz8Z+APNwvsCQQC9
AuaOsReEmMFu8VTjNh2G+TQjgvqKmaQtVNjuOgpUKYv7tYehH3P7/T+62dcy7CRX
cwbLaFbQhUUUD2DCHdkBAkB6CbB+qhu67oE4nnBCXllI9EXktXgFyXv/cScNvM9Y
FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ
-----END RSA PRIVATE KEY-----
WORLD_PORTS: 8000:80
AGAIN_PORTS: 88:80
# hello and again will share the same onion_adress
AGAIN_SERVICE_NAME: foo
HELLO_SERVICE_NAME: foo
# Keep keys in volumes
volumes:
- tor-keys:/var/lib/tor/hidden_service/
hello:
image: tutum/hello-world
hostname: hello
world:
image: tutum/hello-world
hostname: world
again:
image: tutum/hello-world
hostname: again
volumes:
tor-keys:
driver: local

@ -4,7 +4,7 @@ version: "2"
services: services:
tor: tor:
image: goldy/tor-hidden-service image: goldy/tor-hidden-service:$TOR_VERSION
build: . build: .
links: links:
- world - world

@ -4,17 +4,16 @@ version: "2"
services: services:
tor: tor:
image: goldy/tor-hidden-service image: goldy/tor-hidden-service:$TOR_VERSION
build: .
links: links:
- hello - hello
- world - world
- again - again
environment: environment:
# Set mapping ports # Set mapping ports
HELLO_PORTS: 80:80,800:80,8888:80 HELLO_TOR_SERVICE_HOSTS: 80:hello:80,800:hello:80,8888:hello:80
# Set private key # Set private key
HELLO_KEY: | HELLO_TOR_SERVIVE_KEY: |
-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C MIICXQIBAAKBgQDR8TdQF9fDlGhy1SMgfhMBi9TaFeD12/FK27TZE/tYGhxXvs1C
NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH NmFJy1hjVxspF5unmUsCk0yEsvEdcAdp17Vynz6W41VdinETU9yXHlUJ6NyI32AH
@ -31,13 +30,13 @@ services:
FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ FDzzNAAfVc5Nmbmx28Nw+0w6pnpe/3m0Tudbq3nHdHfQ
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
WORLD_PORTS: 8000:80
AGAIN_PORTS: 88:80
# hello and again will share the same onion_adress # hello and again will share the same onion_adress
AGAIN_SERVICE_NAME: foo FOO_TOR_SERVICE_HOSTS: 88:again:80,8000:world:80
HELLO_SERVICE_NAME: foo FOO_TOR_SERVICE_VERSION: '3'
# tor v3 address private key base 64 encoded
FOO_TOR_SERVICE_KEY: |
PT0gZWQyNTUxOXYxLXNlY3JldDogdHlwZTAgPT0AAACArobDQYyZAWXei4QZwr++
j96H1X/gq14NwLRZ2O5DXuL0EzYKkdhZSILY85q+kfwZH8z4ceqe7u1F+0pQi/sM
# Keep keys in volumes # Keep keys in volumes
volumes: volumes:

@ -4,23 +4,19 @@ version: "3.1"
services: services:
tor: tor:
image: goldy/tor-hidden-service image: goldy/tor-hidden-service:$TOR_VERSION
build: .
links: links:
- hello - hello
- world - world
- again - again
environment: environment:
# Set mapping ports # Set version 3 on BAR group
HELLO_PORTS: 80:80,800:80,8888:80 BAR_TOR_SERVICE_HOSTS: '80:hello:80,88:world:80'
BAR_TOR_SERVICE_VERSION: '3'
WORLD_PORTS: 8000:80 # hello and again will share the same v2 onion_adress
FOO_TOR_SERVICE_HOSTS: '88:again:80,80:hello:80,800:hello:80,8888:hello:80'
AGAIN_PORTS: 88:80
# hello and again will share the same onion_adress
AGAIN_SERVICE_NAME: foo
HELLO_SERVICE_NAME: foo
# Keep keys in volumes # Keep keys in volumes
volumes: volumes:
@ -31,6 +27,9 @@ services:
- source: foo - source: foo
target: foo target: foo
mode: 0400 mode: 0400
- source: bar
target: bar
mode: 0400
hello: hello:
image: tutum/hello-world image: tutum/hello-world
@ -50,4 +49,6 @@ volumes:
secrets: secrets:
foo: foo:
file: ./foo_private_key file: ./private_key_foo_v2
bar:
file: ./private_key_bar_v3

@ -0,0 +1,2 @@
#!/bin/bash
git ls-remote --tags https://git.torproject.org/tor.git | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1

Binary file not shown.

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py34, py35, py36 envlist = py34, py35, py36, py37
changedir=assets/onions/ changedir=assets/onions/
setupdir=assets/onions/ setupdir=assets/onions/
skip_missing_interpreters = true skip_missing_interpreters = true

Loading…
Cancel
Save