diff --git a/.env b/.env new file mode 100644 index 0000000..c82f98e --- /dev/null +++ b/.env @@ -0,0 +1,6 @@ +DEBUG=true +HOST=0.0.0.0 +PORT=8000 +API_URL_BASE=https://api.digitalocean.com/v2 +API_TOKEN="" +HTPASSWD=.htpasswd \ No newline at end of file diff --git a/bifrost/__init__.py b/bifrost/__init__.py index 5cac54f..139597f 100644 --- a/bifrost/__init__.py +++ b/bifrost/__init__.py @@ -1,17 +1,2 @@ -from crypt import crypt -import os -def htpasswd(username, password, request): - settings = request.registry.settings - file = settings['biforst.auth'] - if not os.path.isfile(file): - return None - users = {} - with open(file) as f: - for line in f: - login, pwd = line.split(':') - users[login] = pwd.rstrip('\n') - if username in users and crypt(password, users[username]) == users[username]: - return [Authenticated] - return None diff --git a/bifrost/auth.py b/bifrost/auth.py new file mode 100644 index 0000000..c19d226 --- /dev/null +++ b/bifrost/auth.py @@ -0,0 +1,22 @@ +import os +from crypt import crypt + + + +# def setup_auth(app): +# htpasswd: str = app.config.HTPASSWD +# print(htpasswd) +# +# @auth.verify_password +# def htpasswd(username, password): +# if not os.path.isfile(htpasswd): +# return None +# users = {} +# with open(htpasswd) as f: +# for line in f: +# login, pwd = line.split(':') +# users[login] = pwd.rstrip('\n') +# if username in users: +# return crypt(password, users[username]) == users[username] +# else: +# return False diff --git a/bifrost/config.py b/bifrost/config.py new file mode 100644 index 0000000..b062646 --- /dev/null +++ b/bifrost/config.py @@ -0,0 +1,14 @@ +from environs import Env + +env = Env() +env.read_env() # read .env file, if it exists +print("env reloaded") + + +class Settings: + debug: bool = env("DEBUG") + host: str = env("HOST") + port: int = env.int("PORT") + api_url_base: str = env("API_URL_BASE") + api_token: str = env("API_TOKEN") + htpasswd: str = env("HTPASSWD") diff --git a/bifrost/main.py b/bifrost/main.py index 5f2af20..14d03d7 100644 --- a/bifrost/main.py +++ b/bifrost/main.py @@ -1,25 +1,27 @@ -from sanic import Sanic +import uvicorn +from fastapi import FastAPI -from environs import Env +import bifrost.routers as routers +from .config import Settings as settings -from bifrost.settings import Settings +app = FastAPI() -app = Sanic(__name__, load_env='BIFROST_') + +@app.get("/") +async def root(): + return {"message": "Hello World"} + +app.include_router(routers.router) def init(): - env = Env() - env.read_env() + uvicorn.run(app, host=settings.host, port=settings.port) + # app.add_route(update_view, '/update', methods=['GET']) + # # setup_auth(app) - app.config.from_object(Settings) - - from bifrost.views import update_view - app.add_route(update_view, '/update', methods=['GET']) - - app.run(host='0.0.0.0', port=8000, debug=True, access_log=True) - app.run( - host=app.config.HOST, - port=app.config.PORT, - debug=app.config.DEBUG, - access_log=app.config.ACCESS_LOG - ) + # app.run( + # host=app.config.HOST, + # port=app.config.PORT, + # debug=app.config.DEBUG, + # access_log=app.config.ACCESS_LOG + # ) diff --git a/bifrost/routers.py b/bifrost/routers.py new file mode 100644 index 0000000..41b8ddf --- /dev/null +++ b/bifrost/routers.py @@ -0,0 +1,33 @@ +from functools import lru_cache +import logging as logger +from fastapi import APIRouter, Header, Request, Depends + +from .digital_ocean import update_domain +from . import config + +router = APIRouter() + + +@lru_cache() +def get_settings(): + return config.Settings + +@router.get("/update") +def update_view(domain: str, request: Request, ip: str = None, x_forwarded_for: str = Header(None), settings: config.Settings = Depends(get_settings)): + logger.info('Here is your log') + if ip is not None: + current_ip = ip + elif x_forwarded_for is not None: + current_ip = x_forwarded_for + else: + current_ip = request.ip + name, domain = domain.split('.', maxsplit=1) + update_domain(domain, name, current_ip, settings.api_url_base, settings.api_token, logger) + return {"domain": domain, "name": name, "current_ip": current_ip, "api_base": settings.api_url_base, "api_token": settings.api_token} + + +# @forbidden_view_config() +# def basic_challenge(request): +# response = HTTPUnauthorized() +# response.headers.update(forget(request)) +# return response diff --git a/bifrost/settings.py b/bifrost/settings.py deleted file mode 100644 index 2d4f448..0000000 --- a/bifrost/settings.py +++ /dev/null @@ -1,9 +0,0 @@ -from sanic_envconfig import EnvConfig - - -class Settings(EnvConfig): - DEBUG: bool = True - HOST: str = '0.0.0.0' - PORT: int = 8000 - API_URL_BASE: str = 'https://api.digitalocean.com/v2' - API_TOKEN: str = None diff --git a/bifrost/views.py b/bifrost/views.py deleted file mode 100644 index c5ac261..0000000 --- a/bifrost/views.py +++ /dev/null @@ -1,28 +0,0 @@ -from sanic.log import logger -from sanic.response import json - -from bifrost.digital_ocean import update_domain - - -async def update_view(request): - logger.info('Here is your log') - if 'domain' not in request.args or len(request.args['domain']) != 1: - return json({"message": "Domain error"}) - domain = request.args['domain'][0] - if 'ip' in request.args and len(request.args['ip']) == 1: - current_ip = request.args['ip'][0] - else: - if 'X-Forwarded-For' in request.headers: - current_ip = request.headers['X-Forwarded-For'] - else: - current_ip = request.ip - name, domain = domain.split('.', maxsplit=1) - update_domain(domain, name, current_ip, request.app.config.API_URL_BASE, request.app.config.API_TOKEN, logger) - return json({"domain": domain, "name": name, "current_ip": current_ip, "api_base": request.app.config.API_URL_BASE, "api_token": request.app.config.API_TOKEN}) - - -# @forbidden_view_config() -# def basic_challenge(request): -# response = HTTPUnauthorized() -# response.headers.update(forget(request)) -# return response diff --git a/requirements.txt b/requirements.txt index 9b69927..ac51da2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ -wheel -sanic -secure +fastapi +uvicorn environs -sanic-envconfig \ No newline at end of file +requests \ No newline at end of file diff --git a/setup.py b/setup.py index 311d7b8..c38852d 100644 --- a/setup.py +++ b/setup.py @@ -3,20 +3,16 @@ import os from setuptools import setup, find_packages here = os.path.abspath(os.path.dirname(__file__)) -README = open(os.path.join(here, 'README.txt')).read() -CHANGES = open(os.path.join(here, 'CHANGES.txt')).read() - -requires = [ - 'wheel', - 'sanic', - 'secure', - 'environs', - 'sanic-envconfig' - ] +with open(os.path.join(here, 'README.txt'), "r") as r: + README = r.read() +with open(os.path.join(here, 'CHANGES.txt'), "r") as c: + CHANGES = c.read() +with open(os.path.join(here, 'requirements.txt'), "r") as r: + requires = r.read().splitlines() setup(name='bifrost', version='2.0', - description='bifrost', + description='Digital Ocean domain a record updater to use as dyndns', long_description=README + '\n\n' + CHANGES, classifiers=[ "Programming Language :: Python", @@ -26,16 +22,12 @@ setup(name='bifrost', ], author='tanshu', author_email='programming@tanshu.com', - url='https://git.tanshu.com/tanshu', - keywords='web pyramid pylons', + url='https://git.tanshu.com/tanshu/bifrost.git', + keywords='web sanic', packages=find_packages(), include_package_data=True, zip_safe=False, install_requires=requires, tests_require=requires, test_suite="bifrost", - entry_points="""\ - [paste.app_factory] - main = bifrost:main - """, )