Add pre-commit

This commit is contained in:
Christophe Mehay 2017-08-21 00:46:24 +02:00
parent 27dd14ab33
commit f206ea354c
8 changed files with 114 additions and 40 deletions

21
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,21 @@
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: v0.9.1
hooks:
- id: check-added-large-files
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: end-of-file-fixer
- id: flake8
args:
- --exclude=__init__.py
language_version: python3
- id: autopep8-wrapper
language_version: python3
- id: requirements-txt-fixer
- id: trailing-whitespace
- repo: git://github.com/asottile/reorder_python_imports
sha: v0.3.5
hooks:
- id: reorder-python-imports
language_version: python3

View file

@ -4,5 +4,7 @@ python:
- "3.4" - "3.4"
- "3.5" - "3.5"
- "3.6" - "3.6"
install: pip install tox-travis install: pip install tox-travis pre-commit
script: tox script:
- pre-commit run --all-files
- tox

View file

@ -90,6 +90,34 @@ To increase security, it's possible to setup your service through socket between
__Warning__: Due to a bug in `tor` configuration parser, it's not possible to mix network link and socket link in the same `tor` configuration. __Warning__: Due to a bug in `tor` configuration parser, it's not possible to mix network link and socket link in the same `tor` configuration.
### Group services
Multiple services can be hosted behind the same onion address.
```yaml
links:
- hello
- world
- hey
environment:
# Set mapping ports
HELLO_PORTS: 80:80
# Multiple ports can be coma separated
WORLD_PORTS: 8000:80,8888:80,22:22
# Socket mapping is supported
HEY_PORTS: 80:unix:/var/run/socket.sock
# hello and world will share the same onion address
# Service name can be any string as long there is not special char
HELLO_SERVICE_NAME: foo
WORLD_SERVICE_NAME: foo
```
__Warning__: Be carefull to not use the same exposed ports for grouped services.
### Compose v2 support ### Compose v2 support
Links setting are required when using docker-compose v2. See `docker-compose.v2.yml` for example. Links setting are required when using docker-compose v2. See `docker-compose.v2.yml` for example.

View file

@ -1,20 +1,17 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
from json import dumps
from re import match
from pyentrypoint import DockerLinks
import argparse import argparse
import logging
import os
import sys
from json import dumps
from re import match
from jinja2 import Environment from jinja2 import Environment
from jinja2 import FileSystemLoader from jinja2 import FileSystemLoader
from pyentrypoint import DockerLinks
from .Service import ServicesGroup, Service from .Service import Service
from .Service import ServicesGroup
import logging
class Setup(object): class Setup(object):
@ -163,13 +160,10 @@ class Setup(object):
def setup_hosts(self): def setup_hosts(self):
self.setup = {} self.setup = {}
try: self._get_setup_from_env()
self._get_setup_from_env() self._get_setup_from_links()
self._get_setup_from_links() self.check_services()
self.check_services() self.apply_conf()
self.apply_conf()
except BaseException:
raise Exception('Something wrongs with setup')
def check_services(self): def check_services(self):
for group in self.services: for group in self.services:
@ -263,15 +257,26 @@ def main():
help='Setup hosts') help='Setup hosts')
args = parser.parse_args() args = parser.parse_args()
onions = Onions() try:
if args.setup: onions = Onions()
onions.setup_hosts() if args.setup:
return onions.setup_hosts()
onions.torrc_parser() else:
onions.torrc_parser()
except BaseException as e:
error_msg = str(e)
else:
error_msg = None
if args.json: if args.json:
if error_msg:
print(dumps({'error': error_msg}))
sys.exit(1)
logging.getLogger().setLevel(logging.ERROR) logging.getLogger().setLevel(logging.ERROR)
print(onions.to_json()) print(onions.to_json())
else: else:
if error_msg:
logging.error(error_msg)
sys.exit(1)
print(onions) print(onions)

View file

@ -1,12 +1,11 @@
'This class define a service link' 'This class define a service link'
import logging
import os
import re
from base64 import b32encode
from hashlib import sha1
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from hashlib import sha1
from base64 import b32encode
import os
import logging
class ServicesGroup(object): class ServicesGroup(object):
@ -18,6 +17,9 @@ class ServicesGroup(object):
hidden_service_dir = "/var/lib/tor/hidden_service/" hidden_service_dir = "/var/lib/tor/hidden_service/"
def __init__(self, name=None, service=None, hidden_service_dir=None): def __init__(self, name=None, service=None, hidden_service_dir=None):
name_regex = r'^[a-zA-Z0-9-_]+$'
self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir self.hidden_service_dir = hidden_service_dir or self.hidden_service_dir
if not name and not service: if not name and not service:
raise Exception( raise Exception(
@ -25,6 +27,10 @@ class ServicesGroup(object):
) )
self.services = [] self.services = []
self.name = name or service.host self.name = name or service.host
if not re.match(name_regex, self.name):
raise Exception(
'Group {name} has invalid name'.format(name=self.name)
)
if service: if service:
self.add_service(service) self.add_service(service)

View file

@ -1,2 +1,5 @@
from .Onions import Onions, main from .Onions import main
from .Service import ServicesGroup, Service, Ports from .Onions import Onions
from .Service import Ports
from .Service import Service
from .Service import ServicesGroup

View file

@ -33,7 +33,7 @@ setup(
install_requires=['pyentrypoint==0.5.0', install_requires=['pyentrypoint==0.5.0',
'Jinja2>=2.8', 'Jinja2>=2.8',
'pycrypto',], 'pycrypto', ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [

View file

@ -1,13 +1,13 @@
from onions import Onions
import json import json
import os import os
import pytest
import re import re
from Crypto.PublicKey import RSA
from hashlib import sha1
from base64 import b32encode from base64 import b32encode
from hashlib import sha1
import pytest
from Crypto.PublicKey import RSA
from onions import Onions
def get_key_and_onion(): def get_key_and_onion():
key = ''' key = '''
@ -40,6 +40,7 @@ bhJ3M9WzP/EMkAzyW8mVs1moFp3hRcfQlZHl6g1U9D8=
return key.strip(), onion return key.strip(), onion
def get_torrc_template(): def get_torrc_template():
return r''' return r'''
{% for service_group in services %} {% for service_group in services %}
@ -65,6 +66,7 @@ SocksPort 0
# useless line for Jinja bug # useless line for Jinja bug
'''.strip() '''.strip()
def test_ports(monkeypatch): def test_ports(monkeypatch):
env = { env = {
'SERVICE1_PORTS': '80:80', 'SERVICE1_PORTS': '80:80',
@ -104,6 +106,7 @@ def test_ports(monkeypatch):
assert check == 10 assert check == 10
def test_docker_links(fs, monkeypatch): def test_docker_links(fs, monkeypatch):
env = { env = {
@ -186,6 +189,7 @@ def test_key(monkeypatch):
assert onion.services[0].onion_url == onion_url 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', 'SERVICE1_SERVICE_NAME': 'group1',
@ -284,6 +288,7 @@ 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')])
def test_groups(monkeypatch): def test_groups(monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'SERVICE1_SERVICE_NAME': 'group1',
@ -323,6 +328,7 @@ def test_groups(monkeypatch):
assert re.match(onion_match, group.onion_url) assert re.match(onion_match, group.onion_url)
def test_json(monkeypatch): def test_json(monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'SERVICE1_SERVICE_NAME': 'group1',
@ -345,6 +351,7 @@ def test_json(monkeypatch):
assert len(jsn['group1']) == 3 assert len(jsn['group1']) == 3
assert len(jsn['group2']) == 1 assert len(jsn['group2']) == 1
def test_output(monkeypatch): def test_output(monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'SERVICE1_SERVICE_NAME': 'group1',
@ -363,6 +370,7 @@ def test_output(monkeypatch):
for item in ['group1', 'group2', '.onion', ',']: for item in ['group1', 'group2', '.onion', ',']:
assert item in str(onion) assert item in str(onion)
def test_not_valid_share_port(monkeypatch): def test_not_valid_share_port(monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'SERVICE1_SERVICE_NAME': 'group1',
@ -382,6 +390,7 @@ def test_not_valid_share_port(monkeypatch):
onion.check_services() onion.check_services()
assert 'Same port for multiple services' in str(excinfo.value) assert 'Same port for multiple services' in str(excinfo.value)
def test_not_valid_no_services(monkeypatch): def test_not_valid_no_services(monkeypatch):
env = { env = {
'SERVICE1_SERVICE_NAME': 'group1', 'SERVICE1_SERVICE_NAME': 'group1',