From eac64152b8e452f497f1f9888a0c83db1f7cd03d Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Thu, 2 Sep 2021 22:54:22 +0200 Subject: [PATCH] . --- README.md | 51 ++++++++++++++++++++++++++++++++++++--- backend/.gitignore | 1 + backend/poetry.lock | 17 ++++++++++++- backend/public/.gitkeep | 0 backend/pyproject.toml | 1 + backend/tabby/settings.py | 2 ++ backend/tabby/urls.py | 9 ++----- 7 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 backend/public/.gitkeep diff --git a/README.md b/README.md index 425f13e..d6e3cd6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,19 @@ +# Tabby Web + +This is the exact code that runs at https://tabby.sh. In fact, it's being deployed straight out of this repository. + +You can use this to deploy your own copy or to make improvements - pull requests are welcome! + +# How it works + +Tabby Web serves the Tabby Terminal as a web application while managing multiple config files, authentication, and providing TCP connections via a [separate gateway service](https://github.com/Eugeny/tabby-connection-gateway). + +# Requirements + +* Python 3.7+ +* A database server supported by Django (MariaDB, Postgres, SQLite, etc.) +* Storage for distribution files - local, S3, GCS or others supported by `fsspec` + # Using Docker images Tabby Web consists of two Docker images - `backend` and `frontend`. See an example set up in `docker-compose.yml` @@ -6,7 +22,7 @@ Tabby Web consists of two Docker images - `backend` and `frontend`. See an examp ### Frontend -* `BACKEND_URL` +* `BACKEND_URL` (required if running the backend in a separate Docker container). * `WEB_CONCURRENCY` ### Backend @@ -15,8 +31,35 @@ Tabby Web consists of two Docker images - `backend` and `frontend`. See an examp * `FRONTEND_URL` * `APP_DIST_STORAGE`: a `file://`, `s3://`, or `gcs://` URL to store app distros in. * `SOCIAL_AUTH_*_KEY` & `SOCIAL_AUTH_*_SECRET`: social login credentials, supported providers are `GITHUB`, `GITLAB`, `MICROSOFT_GRAPH` and `GOOGLE_OAUTH2`. -* `ENABLE_HOMEPAGE`: set to `False` to disable the homepage and always redirect to the app. -## Installing Tabby app versions +## Adding Tabby app versions -* `docker-compose run backend ./manage.py add_version 1.0.156-nightly.1` +* `docker-compose run backend ./manage.py add_version 1.0.156-nightly.2` + +# Development setup + +Put your environment vars (`DATABASE_URL`, etc.) in the `.env` file in the root of the repo. + +For the frontend: + +```shell +cd frontend +yarn +yarn run build # or yarn run watch +``` + +For the backend: + +```shell +cd backend +poetry install +./manage.py migrate # set up the database +./manage.py add_version 1.0.156-nightly.2 # install an app distribution +PORT=9000 poetry run gunicorn # optionally with --reload +``` + + +# Security + +* When using Tabby Web for SSH/Telnet connectivity, your traffic will pass through a hosted gateway service. It's encrypted in transit (HTTPS) and the gateway servers authenticate themselves with a certificate before connections are made. However there's a non-zero risk of a MITM if a gateway service is compromised and the attacker gains access to the service's private key. +* You can alleviate this risk by [hosting your own gateway service](https://github.com/Eugeny/tabby-connection-gateway), or your own copy of Tabby Web altogether. diff --git a/backend/.gitignore b/backend/.gitignore index 19418ac..a222dce 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,2 +1,3 @@ __pycache__ db.sqlite3 +public diff --git a/backend/poetry.lock b/backend/poetry.lock index 1c907b8..0a2a45d 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -602,6 +602,17 @@ category = "main" optional = false python-versions = ">=3.6.1" +[[package]] +name = "whitenoise" +version = "5.3.0" +description = "Radically simplified static file serving for WSGI applications" +category = "main" +optional = false +python-versions = ">=3.5, <4" + +[package.extras] +brotli = ["brotli"] + [[package]] name = "zipp" version = "3.4.1" @@ -630,7 +641,7 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "a855859b9c8eb70c722c6e1ce320e3b4a8b554b8eeb12e42cfaea4dce857855d" +content-hash = "bb7f88af57c4e8e37ff32e12d3f8627cd64aef874617d88c68fa0f16be8a6de1" [metadata.files] asgiref = [ @@ -949,6 +960,10 @@ websockets = [ {file = "websockets-9.1-cp39-cp39-win_amd64.whl", hash = "sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0"}, {file = "websockets-9.1.tar.gz", hash = "sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3"}, ] +whitenoise = [ + {file = "whitenoise-5.3.0-py2.py3-none-any.whl", hash = "sha256:d963ef25639d1417e8a247be36e6aedd8c7c6f0a08adcb5a89146980a96b577c"}, + {file = "whitenoise-5.3.0.tar.gz", hash = "sha256:d234b871b52271ae7ed6d9da47ffe857c76568f11dd30e28e18c5869dbd11e12"}, +] zipp = [ {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, diff --git a/backend/public/.gitkeep b/backend/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/backend/pyproject.toml b/backend/pyproject.toml index e9eaf37..7588af2 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -23,6 +23,7 @@ pyga = "^2.6.2" django-cors-headers = "^3.7.0" cryptography = "3.0" fsspec = "^2021.7.0" +whitenoise = "^5.3.0" [tool.poetry.dev-dependencies] flake8 = "^3.9.2" diff --git a/backend/tabby/settings.py b/backend/tabby/settings.py index a3e7d68..34ad5b1 100644 --- a/backend/tabby/settings.py +++ b/backend/tabby/settings.py @@ -42,6 +42,7 @@ INSTALLED_APPS = [ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -145,6 +146,7 @@ LOGGING = { STATIC_URL = '/static/' STATICFILES_DIRS = [FRONTEND_BUILD_DIR] +STATIC_ROOT = BASE_DIR / 'public' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' diff --git a/backend/tabby/urls.py b/backend/tabby/urls.py index e180a63..91966bc 100644 --- a/backend/tabby/urls.py +++ b/backend/tabby/urls.py @@ -1,15 +1,10 @@ -from django.conf import settings from django.contrib import admin -from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.urls import path, include -from django.views.static import serve + from .app.urls import urlpatterns as app_urlpatterns urlpatterns = [ path('', include(app_urlpatterns)), path('api/1/auth/social/', include('social_django.urls', namespace='social')), path('admin/', admin.site.urls), - # path(f'{settings.STATIC_URL.strip("/")}/', serve, kwargs={ - # 'document_root': settings.STATIC_ROOT, - # }), -] + staticfiles_urlpatterns(settings.STATIC_URL) +]