This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
from django.urls import reverse
from django.utils.http import urlencode
from allauth.socialaccount.providers.base import Provider, ProviderAccount
class TelegramAccount(ProviderAccount):
pass
class TelegramProvider(Provider):
id = "telegram"
name = "Telegram"
account_class = TelegramAccount
def get_login_url(self, request, **kwargs):
url = reverse("telegram_login")
if kwargs:
url = url + "?" + urlencode(kwargs)
return url
def extract_uid(self, data):
return str(data["id"])
def extract_common_fields(self, data):
ret = {}
if data.get("first_name"):
ret["first_name"] = data.get("first_name")
if data.get("last_name"):
ret["last_name"] = data.get("last_name")
if data.get("username"):
ret["username"] = data.get("username")
return ret
def get_auth_date_validity(self):
auth_date_validity = 30
settings = self.get_settings()
if "AUTH_PARAMS" in settings:
auth_date_validity = settings.get("AUTH_PARAMS").get(
"auth_date_validity", auth_date_validity
)
auth_date_validity = self.app.settings.get(
"auth_date_validity", auth_date_validity
)
return auth_date_validity
provider_classes = [TelegramProvider]

View File

@@ -0,0 +1,19 @@
/* global document, window */
(function () {
'use strict'
const f = document.createElement('form')
f.method = 'POST'
f.action = ''
const fragment = window.location.hash.substr(1)
const fragmentParams = new URLSearchParams(fragment)
for (const param of fragmentParams) {
const d = document.createElement('input')
d.type = 'hidden'
d.name = param[0]
d.value = param[1]
f.appendChild(d)
}
document.body.appendChild(f)
f.submit()
})()

View File

@@ -0,0 +1,6 @@
{% load static %}
<html>
<body>
<script type="text/javascript" src="{% static 'telegram/js/telegram.js' %}"></script>
</body>
</html>

View File

@@ -0,0 +1,9 @@
from django.urls import path
from . import views
urlpatterns = [
path("telegram/login/", views.login, name="telegram_login"),
path("telegram/login/callback/", views.callback, name="telegram_callback"),
]

View File

@@ -0,0 +1,78 @@
import base64
import hashlib
import hmac
import json
import time
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.http import urlencode
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from allauth.socialaccount.adapter import get_adapter
from allauth.socialaccount.helpers import (
complete_social_login,
render_authentication_error,
)
from .provider import TelegramProvider
class LoginView(View):
def dispatch(self, request):
provider = get_adapter().get_provider(request, TelegramProvider.id)
return_to = request.build_absolute_uri(
reverse("telegram_callback") + "?" + request.GET.urlencode()
)
url = "https://oauth.telegram.org/auth?" + urlencode(
{
"origin": request.build_absolute_uri("/"),
"bot_id": provider.app.client_id,
"request_access": "write",
"embed": "0",
"return_to": return_to,
}
)
return HttpResponseRedirect(url)
login = LoginView.as_view()
@method_decorator(csrf_exempt, name="dispatch")
class CallbackView(View):
def get(self, request):
return render(request, "telegram/callback.html")
def post(self, request):
result = request.POST.get("tgAuthResult")
padding = "=" * (4 - (len(result) % 4))
data = json.loads(base64.b64decode(result + padding))
adapter = get_adapter()
provider = adapter.get_provider(request, TelegramProvider.id)
hash = data.pop("hash")
payload = "\n".join(sorted(["{}={}".format(k, v) for k, v in data.items()]))
token = provider.app.secret
token_sha256 = hashlib.sha256(token.encode()).digest()
expected_hash = hmac.new(
token_sha256, payload.encode(), hashlib.sha256
).hexdigest()
auth_date = int(data.pop("auth_date"))
auth_date_validity = provider.get_auth_date_validity()
if hash != expected_hash or time.time() - auth_date > auth_date_validity:
return render_authentication_error(
request, provider_id=provider.id, extra_context={"response": data}
)
login = provider.sociallogin_from_response(request, data)
process = request.GET.get("process")
if process:
login.state["process"] = process
return complete_social_login(request, login)
callback = CallbackView.as_view()