Skip to content

Commit

Permalink
docs: ✏️ django examples (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhaoQi99 authored Dec 3, 2024
1 parent c82108a commit 06257c8
Show file tree
Hide file tree
Showing 22 changed files with 483 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ pip install pyencrypt-pye
✨🍰✨
```
Or you can use `pip install git+https://github.com/ZhaoQi99/pyencrypt-pye.git` install latest version.

## Examples
View examples in the [examples](./examples) directory.

## Usage

```shell
Expand Down
5 changes: 5 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pyencrypt Examples

This directory contains examples of how to use pyencrypt.

* [`django`](./django): Pyencrypt Django Example
42 changes: 42 additions & 0 deletions examples/django/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
FROM python:3.10-bullseye as build

WORKDIR /root/demo

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

ARG PYPI_URL=https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
RUN pip config set global.index-url $PYPI_URL

RUN sed -i '[email protected]@mirrors.aliyun.com@g' /etc/apt/sources.list
RUN sed -i '[email protected]@mirrors.aliyun.com@g' /etc/apt/sources.list

RUN apt update
RUN apt install gettext git vim lrzsz less gcc -y

ADD requirements.txt /root/demo
RUN pip install -r requirements.txt
COPY . /root/demo/

RUN python manage.py collectstatic --noinput

# --- Encryption ---
RUN pip install git+https://github.com/ZhaoQi99/pyencrypt-pye.git
RUN pyencrypt encrypt --in-place --yes .
RUN cp encrypted/loader*.so .
RUN rm -rf encrypted build/

RUN echo "import loader\n$(cat demo/__init__.py)" > demo/__init__.py

COPY manage.py /root/demo
COPY demo/gunicorn.py /root/demo/demo

RUN pip uninstall pyencrypt-pye pycryptodome Cython python-minifier -y
# --- Encryption ---


FROM scratch
COPY --from=build / /

WORKDIR /root/demo
EXPOSE 8000
# ENTRYPOINT [ "bash", "/root/demo/bin/start.sh"]
26 changes: 26 additions & 0 deletions examples/django/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Pyencrypt Django Example

This example shows how to use `pyencrypt` with Django.

## How to use
```shell
docker compose up -d
```

## Test
* runserver: `curl http://127.0.0.1:8001/account/login/?username=admin&password=admin`
* gunicorn: `curl http://127.0.0.1:8002/account/login/?username=admin&password=admin`

## Note
* `manage.py` shouldn't be encrypted.
* `gunicorn.py` shouldn't be encrypted.

### Loader
* Copy `encrypted/loader*.so` to where `manage.py` is located.
* Add `import loader` at the top of `<project>/__init__.py`.
* Don't forget to remove `encrypted` and `build` directory.

### Docker
* For preventing to extract origin layer from image, using [`scratch`](https://docs.docker.com/build/building/base-images/#create-a-base-image) to convert image to single layer.
> [docker: extracting a layer from a image - Stack Overflow](https://stackoverflow.com/questions/40575752/docker-extracting-a-layer-from-a-image)
* Remember to specify `WORKDIR`, `ENTRYPOINT` and other in `Dockerfile` again after `scratch`.
Empty file.
3 changes: 3 additions & 0 deletions examples/django/account/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
6 changes: 6 additions & 0 deletions examples/django/account/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AccountConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'account'
132 changes: 132 additions & 0 deletions examples/django/account/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Generated by Django 4.1.10 on 2024-12-03 05:34

import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.utils.timezone


class Migration(migrations.Migration):

initial = True

dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
]

operations = [
migrations.CreateModel(
name="User",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
(
"date_joined",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
],
options={
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
managers=[
("objects", django.contrib.auth.models.UserManager()),
],
),
]
Empty file.
6 changes: 6 additions & 0 deletions examples/django/account/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
pass
3 changes: 3 additions & 0 deletions examples/django/account/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
9 changes: 9 additions & 0 deletions examples/django/account/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
app_name = "account"

from django.urls import path

from .views import LoginView

urlpatterns = [
path("login/", LoginView.as_view(), name="login"),
]
22 changes: 22 additions & 0 deletions examples/django/account/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.http import JsonResponse
from django.views import View


class LoginView(View):
def get(self, request, *args, **kwargs):
username = request.GET["username"]
password = request.GET["password"]
if username == "admin" and password == "admin":
return JsonResponse(
{
"username": username,
"token": "<token>",
},
)

return JsonResponse(
{
"message": "Invalid password",
},
status=401,
)
11 changes: 11 additions & 0 deletions examples/django/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
demo1:
build: .
command: python manage.py runserver 0.0.0.0:8000
ports:
- 8001:8000
demo2:
build: .
command: gunicorn -c demo/gunicorn.py demo.wsgi
ports:
- 8002:8000
Empty file.
16 changes: 16 additions & 0 deletions examples/django/demo/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for demo project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")

application = get_asgi_application()
6 changes: 6 additions & 0 deletions examples/django/demo/gunicorn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
bind = "0.0.0.0:8000"
workers = 1
worker_class = "gevent"
worker_tmp_dir = "/tmp"
pidfile = "/tmp/gunicorn.pid"
accesslog = "-"
Loading

0 comments on commit 06257c8

Please sign in to comment.