webhook #2
|
@ -0,0 +1,84 @@
|
|||
# Generated by Django 4.2.5 on 2024-06-13 08:08
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('idhub', '0004_alter_event_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='file_datas',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='Date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='file_datas',
|
||||
name='file_name',
|
||||
field=models.CharField(max_length=250, verbose_name='File'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='file_datas',
|
||||
name='success',
|
||||
field=models.BooleanField(default=True, verbose_name='Success'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='schemas',
|
||||
name='_description',
|
||||
field=models.CharField(
|
||||
db_column='description',
|
||||
max_length=250,
|
||||
null=True,
|
||||
verbose_name='Description',
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='schemas',
|
||||
name='_name',
|
||||
field=models.TextField(db_column='name', null=True, verbose_name='Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='schemas',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='Date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='schemas',
|
||||
name='file_schema',
|
||||
field=models.CharField(max_length=250, verbose_name='Schema'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='verificablecredential',
|
||||
name='issued_on',
|
||||
field=models.DateTimeField(null=True, verbose_name='Issued on'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='verificablecredential',
|
||||
name='status',
|
||||
field=models.PositiveSmallIntegerField(
|
||||
choices=[(1, 'Enabled'), (2, 'Issued'), (3, 'Revoked'), (4, 'Expired')],
|
||||
default=1,
|
||||
verbose_name='Status',
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='verificablecredential',
|
||||
name='type',
|
||||
field=models.CharField(max_length=250, verbose_name='Type'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='verificablecredential',
|
||||
name='user',
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='vcredentials',
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name='User',
|
||||
),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 4.2.5 on 2024-06-13 08:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('idhub_auth', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=True, verbose_name='is active'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='is_admin',
|
||||
field=models.BooleanField(default=False, verbose_name='is admin'),
|
||||
),
|
||||
]
|
|
@ -82,7 +82,8 @@ INSTALLED_APPS = [
|
|||
'idhub_auth',
|
||||
'oidc4vp',
|
||||
'idhub',
|
||||
'promotion'
|
||||
'promotion',
|
||||
'webhook'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -26,4 +26,5 @@ urlpatterns = [
|
|||
path('', include('idhub.urls')),
|
||||
path('oidc4vp/', include('oidc4vp.urls')),
|
||||
path('promotion/', include('promotion.urls')),
|
||||
path('webhook/', include('webhook.urls')),
|
||||
]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WebhookConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'webhook'
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# Generated by Django 4.2.5 on 2024-06-13 08:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Token',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID',
|
||||
),
|
||||
),
|
||||
('token', models.UUIDField()),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,7 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
|
||||
|
||||
class Token(models.Model):
|
||||
token = models.UUIDField()
|
|
@ -0,0 +1,67 @@
|
|||
import django_tables2 as tables
|
||||
from django.utils.html import format_html
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from webhook.models import Token
|
||||
|
||||
|
||||
class ButtonColumn(tables.Column):
|
||||
attrs = {
|
||||
"a": {
|
||||
"type": "button",
|
||||
"class": "text-danger",
|
||||
"title": "Remove",
|
||||
}
|
||||
}
|
||||
# it makes no sense to order a column of buttons
|
||||
orderable = False
|
||||
# django_tables will only call the render function if it doesn't find
|
||||
# any empty values in the data, so we stop it from matching the data
|
||||
# to any value considered empty
|
||||
empty_values = ()
|
||||
|
||||
def render(self):
|
||||
return format_html('<i class="bi bi-trash"></i>')
|
||||
|
||||
|
||||
class TokensTable(tables.Table):
|
||||
delete = ButtonColumn(
|
||||
verbose_name=_("Delete"),
|
||||
linkify={
|
||||
"viewname": "webhook:delete_token",
|
||||
"args": [tables.A("pk")]
|
||||
},
|
||||
orderable=False
|
||||
)
|
||||
|
||||
token = tables.Column(verbose_name=_("Token"), empty_values=())
|
||||
|
||||
def render_view_user(self):
|
||||
return format_html('<i class="bi bi-eye"></i>')
|
||||
|
||||
# def render_token(self, record):
|
||||
# return record.get_memberships()
|
||||
|
||||
# def order_membership(self, queryset, is_descending):
|
||||
# # TODO: Test that this doesn't return more rows than it should
|
||||
# queryset = queryset.order_by(
|
||||
# ("-" if is_descending else "") + "memberships__type"
|
||||
# )
|
||||
|
||||
# return (queryset, True)
|
||||
|
||||
# def render_role(self, record):
|
||||
# return record.get_roles()
|
||||
|
||||
# def order_role(self, queryset, is_descending):
|
||||
# queryset = queryset.order_by(
|
||||
# ("-" if is_descending else "") + "roles"
|
||||
# )
|
||||
|
||||
# return (queryset, True)
|
||||
|
||||
class Meta:
|
||||
model = Token
|
||||
template_name = "idhub/custom_table.html"
|
||||
fields = ("token", "view_user")
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{% extends "idhub/base_admin.html" %}
|
||||
{% load i18n %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block content %}
|
||||
<h3>
|
||||
<i class="{{ icon }}"></i>
|
||||
{{ subtitle }}
|
||||
</h3>
|
||||
{% render_table table %}
|
||||
<div class="form-actions-no-box">
|
||||
<a class="btn btn-green-admin" href="{% url 'webhook:new_token' %}">{% translate "Generate a new token" %} <i class="bi bi-plus"></i></a>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -0,0 +1,13 @@
|
|||
from webhook import views
|
||||
|
||||
from django.urls import path
|
||||
|
||||
|
||||
app_name = 'webhook'
|
||||
|
||||
urlpatterns = [
|
||||
path('verify/', views.webhook_verify, name='verify'),
|
||||
path('tokens/', views.WebHookTokenView.as_view(), name='tokens'),
|
||||
path('tokens/new', views.TokenNewView.as_view(), name='new_token'),
|
||||
path('tokens/<int:pk>/del', views.TokenDeleteView.as_view(), name='delete_token'),
|
||||
]
|
|
@ -0,0 +1,96 @@
|
|||
import json
|
||||
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic.edit import DeleteView
|
||||
from django.views.generic.base import View
|
||||
from django.http import JsonResponse
|
||||
from django_tables2 import SingleTableView
|
||||
from pyvckit.verify import verify_vp, verify_vc
|
||||
from uuid import uuid4
|
||||
|
||||
from idhub.mixins import AdminView
|
||||
from webhook.models import Token
|
||||
from webhook.tables import TokensTable
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def webhook_verify(request):
|
||||
if request.method == 'POST':
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if not auth_header or not auth_header.startswith('Bearer '):
|
||||
return JsonResponse({'error': 'Invalid or missing token'}, status=401)
|
||||
|
||||
token = auth_header.split(' ')[1]
|
||||
tk = Token.objects.filter(token=token).first()
|
||||
if not tk:
|
||||
return JsonResponse({'error': 'Invalid or missing token'}, status=401)
|
||||
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({'error': 'Invalid JSON'}, status=400)
|
||||
|
||||
typ = data.get("type")
|
||||
vc = data.get("data")
|
||||
try:
|
||||
vc = json.dumps(vc)
|
||||
except Exception:
|
||||
return JsonResponse({'error': 'Invalid JSON'}, status=400)
|
||||
|
||||
func = verify_vp
|
||||
if typ == "credential":
|
||||
func = verify_vc
|
||||
|
||||
if func(vc):
|
||||
return JsonResponse({'status': 'success'}, status=200)
|
||||
|
||||
return JsonResponse({'status': 'fail'}, status=200)
|
||||
|
||||
return JsonResponse({'error': 'Invalid request method'}, status=400)
|
||||
|
||||
|
||||
class WebHookTokenView(AdminView, SingleTableView):
|
||||
template_name = "token.html"
|
||||
title = _('Token')
|
||||
section = ""
|
||||
subtitle = _('Managament Tokens')
|
||||
icon = 'bi bi-key'
|
||||
model = Token
|
||||
table_class = TokensTable
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Override the get_queryset method to filter events based on the user type.
|
||||
"""
|
||||
return Token.objects.filter().order_by("-id")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context.update({
|
||||
'tokens': Token.objects,
|
||||
})
|
||||
return context
|
||||
|
||||
|
||||
class TokenDeleteView(AdminView, DeleteView):
|
||||
model = Token
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.check_valid_user()
|
||||
self.pk = kwargs['pk']
|
||||
self.object = get_object_or_404(self.model, pk=self.pk)
|
||||
self.object.delete()
|
||||
|
||||
return redirect('webhook:tokens')
|
||||
|
||||
|
||||
class TokenNewView(AdminView, View):
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.check_valid_user()
|
||||
Token.objects.create(token=uuid4())
|
||||
|
||||
return redirect('webhook:tokens')
|
||||
|
Loading…
Reference in New Issue