diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..585e2ab
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,23 @@
+# http://editorconfig.org
+
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.{py,rst,ini}]
+indent_style = space
+indent_size = 4
+
+[*.{html,css,scss,json,yml}]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
diff --git a/.gitignore b/.gitignore
index 3555fa8..9f6e64d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,159 @@
-*.pyc
-*~
-*.tmp
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+__pycache__
+
+# C extensions
+*.so
+
+# If you are using PyCharm #
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/gradle.xml
+.idea/**/libraries
+*.iws /out/
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+-# Mr Developer
+-.mr.developer.cfg
+-.project
+-.pydevproject
+
+-# Sphinx
+-docs/_build
+
+-# Complexity
+-output/*.html
+-output/*/index.html
+
+-example/db.sqlite3
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1f4bce8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,43 @@
+MIT License
+
+Copyright (c) 2018 Alexander Tereshkin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+MIT License
+
+Copyright (c) 2018 Bearle
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..3b00ea8
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+recursive-include web3auth *.html *.png *.gif *js *.css *jpg *jpeg *svg *py
diff --git a/README.md b/README.md
index 3060c36..a469f47 100644
--- a/README.md
+++ b/README.md
@@ -1,33 +1,78 @@
-# Django-Web3-Auth
+# django-web3-auth
-django-web3-auth is a pluggable Django app that enables login/signup via an Ethereum wallet (a la CryptoKitties). The user authenticates themselves by digitally signing the session key with their wallet's private key.
+django-web3-auth is a pluggable Django app that enables login/signup via an Ethereum wallet (specifically MetaMask).
+The user authenticates themselves by digitally signing the session key with their wallet's private key.
+
+Use with django >= 3.2.0, python >= 3.9
-## Installation
-
-django-web3-auth has no releases yet, you'll need to install it from repository:
+## Quickstart
+Install django-web3-auth with pip:
```bash
-pip install https://github.com/atereshkin/django-web3-auth/archive/master.zip
+pip install git+ssh://git@github.com/krilarite/django-web3-auth.git
```
-
-You will also need [Web3.js](https://github.com/ethereum/web3.js) included in your pages.
-
-## Usage
-
-1. Add `'web3auth'` to the `INSTALLED_APPS` setting
-2. Set `'web3auth.backend.Web3Backend'` as your authentication backend:
+Add it to your INSTALLED_APPS:
+```python
+INSTALLED_APPS = [
+ ...
+ 'web3auth',
+ ...
+]
+```
+Set 'web3auth.backend.Web3Backend' as your authentication backend:
```python
-AUTHENTICATION_BACKENDS = ['web3auth.backend.Web3Backend']
+AUTHENTICATION_BACKENDS = [
+ 'django.contrib.auth.backends.ModelBackend',
+ 'web3auth.backend.Web3Backend'
+]
```
-3. Bind some URLs to `web3auth.views.login_view` and `web3auth.views.signup_view`. Both views take an optional `template_name` argument.
+Set a field from the User model for storing the users' ETH address:
```python
-from django.conf.urls import url
-
-from web3auth import views as web3auth_views
+WEB3AUTH_USER_ADDRESS_FIELD = 'username'
+```
+Add Django-Web3-Auth's URL patterns:
+```python
+from web3auth import urls as web3auth_urls
urlpatterns = [
- url(r'^login/$', web3auth_views.login_view, {'template_name' : 'login.html'}, name='login'),
- url(r'^signup/$', web3auth_views.signup_view, name='signup'),
+ ...
+ path('', include(web3auth_urls)),
+ ...
]
+```
+Add some javascript to handle login:
+```html
+
+
+```
+Implement a login button:
+```html
+
+
+```
+MetaMask will prompt you to sign a message and you'll be logged in afterwards.
+
+## Contributing
+Clone the project
+```bash
+git clone git@github.com:krilarite/django-web3-auth.git
+```
+Set up a virtualenv
+```
+mkvirtualenv -p /usr/bin/python3.9 -a `pwd` django-web3-auth
+pip install -r requirements.txt
+```
+Use the example project for testing
+```bash
+cd example
+python manage.py migrate
+python manage.py runserver
```
-4. Code your templates for login and signup pages. Example code can be found in [login.html](web3auth/templates/web3auth/login.html) and [signup.html](web3auth/templates/web3auth/signup.html)
+Navigate to `localhost:8000/login` and you'll see a login page.
diff --git a/example/README.md b/example/README.md
new file mode 100644
index 0000000..2fd8290
--- /dev/null
+++ b/example/README.md
@@ -0,0 +1,25 @@
+Example Project for web3auth
+
+This example is provided as a convenience feature to allow potential users to try the app straight from the app repo without having to create a django project.
+
+It can also be used to develop the app in place.
+
+To run this example, follow these instructions:
+
+1. Clone the repository
+2. Navigate to the `example` directory
+3. Install the requirements for the package (probably in a virtualenv):
+
+ pip install -r requirements.txt
+
+4. Make and apply migrations
+
+ python manage.py makemigrations
+
+ python manage.py migrate
+
+5. Run the server
+
+ python manage.py runserver
+
+6. Access from the browser at `http://127.0.0.1:8000`
diff --git a/web3auth/migrations/__init__.py b/example/example/__init__.py
similarity index 100%
rename from web3auth/migrations/__init__.py
rename to example/example/__init__.py
diff --git a/example/example/settings.py b/example/example/settings.py
new file mode 100644
index 0000000..1551dfd
--- /dev/null
+++ b/example/example/settings.py
@@ -0,0 +1,124 @@
+"""
+Django settings for example project.
+
+Generated by Cookiecutter Django Package
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.9/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.9/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = "11111111111111111111111111111111111111111111111111"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+
+ 'web3auth',
+
+ # if your app has other dependencies that need to be added to the site
+ # they should be added here
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'example.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'example.wsgi.application'
+
+# Database
+# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+
+# Password validation
+# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+AUTHENTICATION_BACKENDS = [
+ 'django.contrib.auth.backends.ModelBackend',
+ 'web3auth.backend.Web3Backend'
+]
+# Internationalization
+# https://docs.djangoproject.com/en/1.9/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.9/howto/static-files/
+
+STATIC_URL = '/static/'
+LOGIN_REDIRECT_URL = '/user/'
diff --git a/example/example/urls.py b/example/example/urls.py
new file mode 100644
index 0000000..c3988e1
--- /dev/null
+++ b/example/example/urls.py
@@ -0,0 +1,43 @@
+"""example URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/1.9/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.conf.urls import url, include
+ 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
+"""
+from django.conf.urls import url, include
+from django.contrib import admin
+from django.urls import path, include
+from django.contrib.auth import logout
+
+from django.shortcuts import render, redirect
+
+
+def login(request):
+ return render(request, 'web3auth/login.html')
+
+
+def logout_view(request):
+ logout(request)
+ return redirect('login')
+
+
+def user_view(request):
+ return render(request, 'web3auth/user.html')
+
+
+urlpatterns = [
+ path('admin/', admin.site.urls),
+ path('login/', login, name='login'),
+ path('user/', user_view, name='user'),
+ path('', include('web3auth.urls', namespace='web3auth')),
+ path('logout/', logout_view, name='logout'),
+]
diff --git a/example/example/wsgi.py b/example/example/wsgi.py
new file mode 100644
index 0000000..fd6d782
--- /dev/null
+++ b/example/example/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for example project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
+
+application = get_wsgi_application()
diff --git a/example/manage.py b/example/manage.py
new file mode 100755
index 0000000..2605e37
--- /dev/null
+++ b/example/manage.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
+
+ from django.core.management import execute_from_command_line
+
+ execute_from_command_line(sys.argv)
diff --git a/example/requirements.txt b/example/requirements.txt
new file mode 100644
index 0000000..1bea32d
--- /dev/null
+++ b/example/requirements.txt
@@ -0,0 +1,7 @@
+# Your app requirements.
+-r ../requirements_test.txt
+
+# Your app in editable mode.
+-e ../
+Django==2.0.6
+packaging==16.8
diff --git a/example/templates/web3auth/base.html b/example/templates/web3auth/base.html
new file mode 100644
index 0000000..f9b69f1
--- /dev/null
+++ b/example/templates/web3auth/base.html
@@ -0,0 +1,65 @@
+{% load static i18n %}
+
+
+