add unstaged changes
This commit is contained in:
parent
c677cebde5
commit
3ab022f45d
@ -5,7 +5,7 @@ import hashlib
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
import nacl.signing
|
import nacl.signing
|
||||||
from binascii import hexlify
|
from binascii import hexlify, unhexlify
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import time
|
import time
|
||||||
@ -67,12 +67,20 @@ def createPost(newsgroup, ref, form, files, secretKey=None):
|
|||||||
msg['Date'] = email.utils.format_datetime(datetime.now())
|
msg['Date'] = email.utils.format_datetime(datetime.now())
|
||||||
if ref and not msgid_valid(ref):
|
if ref and not msgid_valid(ref):
|
||||||
return None, "invalid reference: {}".format(ref)
|
return None, "invalid reference: {}".format(ref)
|
||||||
if ref:
|
|
||||||
msg["References"] = ref
|
|
||||||
msg["Newsgroups"] = newsgroup
|
msg["Newsgroups"] = newsgroup
|
||||||
name = "Anonymous"
|
name = "Anonymous"
|
||||||
if 'name' in form:
|
if 'name' in form:
|
||||||
name = form['name'] or name
|
name = form['name'] or name
|
||||||
|
if '#' in name:
|
||||||
|
parts = name.split('#')
|
||||||
|
secret = name[1+len(name):]
|
||||||
|
name = parts[0]
|
||||||
|
try:
|
||||||
|
assert len(unhexlify(secret.encode('ascii'))) == 32
|
||||||
|
except:
|
||||||
|
secret = hashlib.sha256(secret.encode('utf-8')).hexdigest()
|
||||||
|
secretKey = secret
|
||||||
|
|
||||||
msg["From"] = '{} <anon@django.nntpchan.tld>'.format(name)
|
msg["From"] = '{} <anon@django.nntpchan.tld>'.format(name)
|
||||||
if 'attachment' in files:
|
if 'attachment' in files:
|
||||||
msg['Content-Type'] = 'multipart/mixed'
|
msg['Content-Type'] = 'multipart/mixed'
|
||||||
@ -93,6 +101,10 @@ def createPost(newsgroup, ref, form, files, secretKey=None):
|
|||||||
m = '{}'.format(form['message'] or ' ')
|
m = '{}'.format(form['message'] or ' ')
|
||||||
msg.set_payload(m)
|
msg.set_payload(m)
|
||||||
msg['Message-Id'] = '<{}${}@{}>'.format(randstr(5), int(time_int(datetime.now())), settings.FRONTEND_NAME)
|
msg['Message-Id'] = '<{}${}@{}>'.format(randstr(5), int(time_int(datetime.now())), settings.FRONTEND_NAME)
|
||||||
|
if ref:
|
||||||
|
msg["References"] = ref
|
||||||
|
else:
|
||||||
|
msg["References"] = msg["Message-Id"]
|
||||||
if secretKey:
|
if secretKey:
|
||||||
msg['Path'] = settings.FRONTEND_NAME
|
msg['Path'] = settings.FRONTEND_NAME
|
||||||
# sign
|
# sign
|
||||||
@ -103,7 +115,11 @@ def createPost(newsgroup, ref, form, files, secretKey=None):
|
|||||||
body = msg.as_bytes()
|
body = msg.as_bytes()
|
||||||
h.update(body)
|
h.update(body)
|
||||||
sig = hexlify(keypair.sign(h.digest()).signature).decode('ascii')
|
sig = hexlify(keypair.sign(h.digest()).signature).decode('ascii')
|
||||||
data = '''Content-Type: message/rfc822; charset=UTF-8
|
if ref:
|
||||||
|
data = 'References: ' + ref + '\n'
|
||||||
|
else:
|
||||||
|
data = ''
|
||||||
|
data += '''Content-Type: message/rfc822; charset=UTF-8
|
||||||
Message-ID: {}
|
Message-ID: {}
|
||||||
Content-Transfer-Encoding: 8bit
|
Content-Transfer-Encoding: 8bit
|
||||||
Newsgroups: {}
|
Newsgroups: {}
|
||||||
@ -113,7 +129,7 @@ From: {}
|
|||||||
Date: {}
|
Date: {}
|
||||||
Subject: {}
|
Subject: {}
|
||||||
|
|
||||||
{}'''.format(msg["Message-ID"], newsgroup, pubkey, sig, msg["From"], msg["Date"], msg['Subject'], msg.as_string())
|
{}\n'''.format(msg["Message-ID"], msg["Refereces"], newsgroup, pubkey, sig, msg["From"], msg["Date"], msg['Subject'], msg.as_string())
|
||||||
data = data.encode('utf-8')
|
data = data.encode('utf-8')
|
||||||
else:
|
else:
|
||||||
data = msg.as_bytes()
|
data = msg.as_bytes()
|
||||||
@ -131,3 +147,17 @@ Subject: {}
|
|||||||
if ref:
|
if ref:
|
||||||
return ref, None
|
return ref, None
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
def verify_message(pubkey, sig, payload):
|
||||||
|
h = hashlib.sha512()
|
||||||
|
h.update(payload[:-1])
|
||||||
|
d = h.digest()
|
||||||
|
sig = unhexlify(sig)
|
||||||
|
k = nacl.signing.VerifyKey(pubkey, nacl.signing.encoding.HexEncoder)
|
||||||
|
try:
|
||||||
|
k.verify(d, sig)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
@ -200,10 +200,23 @@ class ModView(generic.View, Postable):
|
|||||||
return render(request, 'frontend/redirect.html', {'url' : reverse('frontend:mod'), 'msg' : msg } )
|
return render(request, 'frontend/redirect.html', {'url' : reverse('frontend:mod'), 'msg' : msg } )
|
||||||
else:
|
else:
|
||||||
# do mod action
|
# do mod action
|
||||||
return self.handle_mod_action(request)
|
return self.handle_mod_action(request, mod, action)
|
||||||
|
|
||||||
def handle_mod_action(self, request):
|
def handle_mod_action(self, request, mod, action):
|
||||||
return render(request, 'frontend/redirect.html', {'url' : reverse('frontend:mod')} )
|
msg = 'no action made'
|
||||||
|
if action is not None:
|
||||||
|
if action == 'delete':
|
||||||
|
# handle bulk delete
|
||||||
|
if 'posts' in request.POST:
|
||||||
|
body = '\ndelete '.join(request.POST['posts'].split())
|
||||||
|
sk = mod['sk']
|
||||||
|
_, err = util.createPost('ctl', '', {'message' : body }, {}, sk)
|
||||||
|
if err:
|
||||||
|
msg = 'error: {}'.format(err)
|
||||||
|
else:
|
||||||
|
msg = 'okay'
|
||||||
|
|
||||||
|
return render(request, 'frontend/redirect.html', {'url' : reverse('frontend:mod'), 'msg' : msg} )
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
mod = None
|
mod = None
|
||||||
|
@ -7,5 +7,4 @@
|
|||||||
<input type="hidden" name="action" value="login"></input>
|
<input type="hidden" name="action" value="login"></input>
|
||||||
<input type="submit" value="login"></input>
|
<input type="submit" value="login"></input>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
<input type="hidden" name="action" value="logout"></input>
|
<input type="hidden" name="action" value="logout"></input>
|
||||||
<input type="submit" value="logout"></input>
|
<input type="submit" value="logout"></input>
|
||||||
</form>
|
</form>
|
||||||
mod page
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="action" value="delete"></input>
|
||||||
|
<label for="bulk-delete"> bulk delete</label>
|
||||||
|
<textarea name="posts"></textarea>
|
||||||
|
<input type="submit" value="delete"></input>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -3,7 +3,7 @@ from django.http import HttpResponse, HttpResponseNotAllowed, JsonResponse
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from .frontend.models import Post, Attachment, Newsgroup
|
from .frontend.models import Post, Attachment, Newsgroup, ModPriv
|
||||||
from .frontend import util
|
from .frontend import util
|
||||||
|
|
||||||
from . import thumbnail
|
from . import thumbnail
|
||||||
@ -28,9 +28,20 @@ def webhook(request):
|
|||||||
"""
|
"""
|
||||||
if request.method != 'POST':
|
if request.method != 'POST':
|
||||||
return HttpResponseNotAllowed(['POST'])
|
return HttpResponseNotAllowed(['POST'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msg = email.message_from_bytes(request.body)
|
msg = email.message_from_bytes(request.body)
|
||||||
|
process_message(msg)
|
||||||
|
except Exception as ex:
|
||||||
|
traceback.print_exc()
|
||||||
|
return JsonResponse({ 'error': '{}'.format(ex) })
|
||||||
|
else:
|
||||||
|
return JsonResponse({'posted': True})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def process_message(msg):
|
||||||
|
|
||||||
newsgroup = msg.get('Newsgroups')
|
newsgroup = msg.get('Newsgroups')
|
||||||
|
|
||||||
if newsgroup is None:
|
if newsgroup is None:
|
||||||
@ -80,6 +91,7 @@ def webhook(request):
|
|||||||
'name': name,
|
'name': name,
|
||||||
'subject': msg["Subject"] or '',
|
'subject': msg["Subject"] or '',
|
||||||
'newsgroup': group}, msgid=msgid)
|
'newsgroup': group}, msgid=msgid)
|
||||||
|
|
||||||
if not created:
|
if not created:
|
||||||
post.subject = msg["Subject"] or ''
|
post.subject = msg["Subject"] or ''
|
||||||
post.name = name
|
post.name = name
|
||||||
@ -88,8 +100,19 @@ def webhook(request):
|
|||||||
|
|
||||||
for part in msg.walk():
|
for part in msg.walk():
|
||||||
ctype = part.get_content_type()
|
ctype = part.get_content_type()
|
||||||
|
print (ctype)
|
||||||
if ctype.startswith("text/plain"):
|
if ctype.startswith("text/plain"):
|
||||||
m += '{} '.format(part.get_payload(decode=True).decode('utf-8'))
|
m += '{} '.format(part.get_payload(decode=True).decode('utf-8'))
|
||||||
|
elif ctype.startswith("message/rfc822"):
|
||||||
|
# signed message
|
||||||
|
payload = part.get_payload()
|
||||||
|
if payload is None:
|
||||||
|
raise Exception('invalid signed message, no body')
|
||||||
|
for inner in payload:
|
||||||
|
if not util.verify_message(msg["X-Pubkey-Ed25519"], msg['X-Signature-Ed25519-Sha512'], inner.as_bytes()):
|
||||||
|
raise Exception('invalid signed message, signature failed')
|
||||||
|
process_message(inner)
|
||||||
|
print('processed inner')
|
||||||
else:
|
else:
|
||||||
payload = part.get_payload(decode=True)
|
payload = part.get_payload(decode=True)
|
||||||
if payload is None:
|
if payload is None:
|
||||||
@ -116,6 +139,7 @@ def webhook(request):
|
|||||||
post.message = m
|
post.message = m
|
||||||
post.save()
|
post.save()
|
||||||
|
|
||||||
|
|
||||||
for att in atts:
|
for att in atts:
|
||||||
if post.has_attachment(att.filehash):
|
if post.has_attachment(att.filehash):
|
||||||
continue
|
continue
|
||||||
@ -134,10 +158,3 @@ def webhook(request):
|
|||||||
op.bump(post.posted)
|
op.bump(post.posted)
|
||||||
op.save()
|
op.save()
|
||||||
|
|
||||||
except Exception as ex:
|
|
||||||
traceback.print_exc()
|
|
||||||
return JsonResponse({ 'error': '{}'.format(ex) })
|
|
||||||
else:
|
|
||||||
return JsonResponse({'posted': True})
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user