add unstaged changes
This commit is contained in:
parent
c677cebde5
commit
3ab022f45d
@ -5,7 +5,7 @@ import hashlib
|
||||
import re
|
||||
|
||||
import nacl.signing
|
||||
from binascii import hexlify
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
from datetime import datetime
|
||||
import time
|
||||
@ -67,12 +67,20 @@ def createPost(newsgroup, ref, form, files, secretKey=None):
|
||||
msg['Date'] = email.utils.format_datetime(datetime.now())
|
||||
if ref and not msgid_valid(ref):
|
||||
return None, "invalid reference: {}".format(ref)
|
||||
if ref:
|
||||
msg["References"] = ref
|
||||
msg["Newsgroups"] = newsgroup
|
||||
name = "Anonymous"
|
||||
if 'name' in form:
|
||||
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)
|
||||
if 'attachment' in files:
|
||||
msg['Content-Type'] = 'multipart/mixed'
|
||||
@ -93,6 +101,10 @@ def createPost(newsgroup, ref, form, files, secretKey=None):
|
||||
m = '{}'.format(form['message'] or ' ')
|
||||
msg.set_payload(m)
|
||||
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:
|
||||
msg['Path'] = settings.FRONTEND_NAME
|
||||
# sign
|
||||
@ -103,7 +115,11 @@ def createPost(newsgroup, ref, form, files, secretKey=None):
|
||||
body = msg.as_bytes()
|
||||
h.update(body)
|
||||
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: {}
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Newsgroups: {}
|
||||
@ -113,7 +129,7 @@ From: {}
|
||||
Date: {}
|
||||
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')
|
||||
else:
|
||||
data = msg.as_bytes()
|
||||
@ -131,3 +147,17 @@ Subject: {}
|
||||
if ref:
|
||||
return ref, 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 } )
|
||||
else:
|
||||
# do mod action
|
||||
return self.handle_mod_action(request)
|
||||
return self.handle_mod_action(request, mod, action)
|
||||
|
||||
def handle_mod_action(self, request):
|
||||
return render(request, 'frontend/redirect.html', {'url' : reverse('frontend:mod')} )
|
||||
def handle_mod_action(self, request, mod, action):
|
||||
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):
|
||||
mod = None
|
||||
|
@ -7,5 +7,4 @@
|
||||
<input type="hidden" name="action" value="login"></input>
|
||||
<input type="submit" value="login"></input>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -5,6 +5,13 @@
|
||||
<input type="hidden" name="action" value="logout"></input>
|
||||
<input type="submit" value="logout"></input>
|
||||
</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 %}
|
||||
|
@ -3,7 +3,7 @@ from django.http import HttpResponse, HttpResponseNotAllowed, JsonResponse
|
||||
from django.shortcuts import render
|
||||
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 . import thumbnail
|
||||
@ -28,112 +28,9 @@ def webhook(request):
|
||||
"""
|
||||
if request.method != 'POST':
|
||||
return HttpResponseNotAllowed(['POST'])
|
||||
|
||||
try:
|
||||
msg = email.message_from_bytes(request.body)
|
||||
newsgroup = msg.get('Newsgroups')
|
||||
|
||||
if newsgroup is None:
|
||||
raise Exception("no newsgroup specified")
|
||||
|
||||
if not util.newsgroup_valid(newsgroup):
|
||||
raise Exception("invalid newsgroup name")
|
||||
|
||||
bump = True
|
||||
group, created = Newsgroup.objects.get_or_create(name=newsgroup)
|
||||
if created:
|
||||
group.save()
|
||||
if group.banned:
|
||||
raise Exception("newsgroup is banned")
|
||||
|
||||
msgid = None
|
||||
for h in ('Message-ID', 'Message-Id', 'MessageId', 'MessageID'):
|
||||
if h in msg:
|
||||
msgid = msg[h]
|
||||
break
|
||||
# check for sage
|
||||
if 'X-Sage' in msg and msg['X-Sage'] == '1':
|
||||
bump = False
|
||||
|
||||
if msgid is None:
|
||||
raise Exception("no message id specified")
|
||||
elif not util.msgid_valid(msgid):
|
||||
raise Exception("invalid message id format: {}".format(msgid))
|
||||
|
||||
opmsgid = msgid
|
||||
|
||||
h = util.hashid(msgid)
|
||||
atts = list()
|
||||
ref = msg['References'] or ''
|
||||
posted = util.time_int(email.utils.parsedate_to_datetime(msg['Date']))
|
||||
|
||||
if len(ref) > 0:
|
||||
opmsgid = ref
|
||||
|
||||
f = msg['From'] or 'anon <anon@anon>'
|
||||
name = email.utils.parseaddr(f)[0]
|
||||
post, created = Post.objects.get_or_create(defaults={
|
||||
'posthash': h,
|
||||
'reference': ref,
|
||||
'posted': posted,
|
||||
'last_bumped': 0,
|
||||
'name': name,
|
||||
'subject': msg["Subject"] or '',
|
||||
'newsgroup': group}, msgid=msgid)
|
||||
if not created:
|
||||
post.subject = msg["Subject"] or ''
|
||||
post.name = name
|
||||
post.posted = posted
|
||||
m = ''
|
||||
|
||||
for part in msg.walk():
|
||||
ctype = part.get_content_type()
|
||||
if ctype.startswith("text/plain"):
|
||||
m += '{} '.format(part.get_payload(decode=True).decode('utf-8'))
|
||||
else:
|
||||
payload = part.get_payload(decode=True)
|
||||
if payload is None:
|
||||
continue
|
||||
filename = part.get_filename()
|
||||
mtype = part.get_content_type()
|
||||
ext = filename.split('.')[-1].lower()
|
||||
fh = util.hashfile(bytes(payload))
|
||||
fn = fh + '.' + ext
|
||||
fname = os.path.join(settings.MEDIA_ROOT, fn)
|
||||
if not os.path.exists(fname):
|
||||
with open(fname, 'wb') as f:
|
||||
f.write(payload)
|
||||
tname = os.path.join(settings.MEDIA_ROOT, 'thumb-{}.jpg'.format(fn))
|
||||
placeholder = os.path.join(settings.ASSETS_ROOT, 'placeholder.jpg')
|
||||
if not os.path.exists(tname):
|
||||
thumbnail.generate(fname, tname, placeholder)
|
||||
|
||||
att = Attachment(filehash=fh)
|
||||
att.mimetype = mtype
|
||||
att.filename = filename
|
||||
att.save()
|
||||
atts.append(att)
|
||||
post.message = m
|
||||
post.save()
|
||||
|
||||
for att in atts:
|
||||
if post.has_attachment(att.filehash):
|
||||
continue
|
||||
post.attachments.add(att)
|
||||
|
||||
|
||||
op, _ = Post.objects.get_or_create(defaults={
|
||||
'posthash': util.hashid(opmsgid),
|
||||
'reference': '',
|
||||
'posted': 0,
|
||||
'last_bumped': 0,
|
||||
'name': 'OP',
|
||||
'subject': 'OP Not Found',
|
||||
'newsgroup': group}, msgid=opmsgid)
|
||||
if bump:
|
||||
op.bump(post.posted)
|
||||
op.save()
|
||||
|
||||
process_message(msg)
|
||||
except Exception as ex:
|
||||
traceback.print_exc()
|
||||
return JsonResponse({ 'error': '{}'.format(ex) })
|
||||
@ -141,3 +38,123 @@ def webhook(request):
|
||||
return JsonResponse({'posted': True})
|
||||
|
||||
|
||||
|
||||
|
||||
def process_message(msg):
|
||||
|
||||
newsgroup = msg.get('Newsgroups')
|
||||
|
||||
if newsgroup is None:
|
||||
raise Exception("no newsgroup specified")
|
||||
|
||||
if not util.newsgroup_valid(newsgroup):
|
||||
raise Exception("invalid newsgroup name")
|
||||
|
||||
bump = True
|
||||
group, created = Newsgroup.objects.get_or_create(name=newsgroup)
|
||||
if created:
|
||||
group.save()
|
||||
if group.banned:
|
||||
raise Exception("newsgroup is banned")
|
||||
|
||||
msgid = None
|
||||
for h in ('Message-ID', 'Message-Id', 'MessageId', 'MessageID'):
|
||||
if h in msg:
|
||||
msgid = msg[h]
|
||||
break
|
||||
# check for sage
|
||||
if 'X-Sage' in msg and msg['X-Sage'] == '1':
|
||||
bump = False
|
||||
|
||||
if msgid is None:
|
||||
raise Exception("no message id specified")
|
||||
elif not util.msgid_valid(msgid):
|
||||
raise Exception("invalid message id format: {}".format(msgid))
|
||||
|
||||
opmsgid = msgid
|
||||
|
||||
h = util.hashid(msgid)
|
||||
atts = list()
|
||||
ref = msg['References'] or ''
|
||||
posted = util.time_int(email.utils.parsedate_to_datetime(msg['Date']))
|
||||
|
||||
if len(ref) > 0:
|
||||
opmsgid = ref
|
||||
|
||||
f = msg['From'] or 'anon <anon@anon>'
|
||||
name = email.utils.parseaddr(f)[0]
|
||||
post, created = Post.objects.get_or_create(defaults={
|
||||
'posthash': h,
|
||||
'reference': ref,
|
||||
'posted': posted,
|
||||
'last_bumped': 0,
|
||||
'name': name,
|
||||
'subject': msg["Subject"] or '',
|
||||
'newsgroup': group}, msgid=msgid)
|
||||
|
||||
if not created:
|
||||
post.subject = msg["Subject"] or ''
|
||||
post.name = name
|
||||
post.posted = posted
|
||||
m = ''
|
||||
|
||||
for part in msg.walk():
|
||||
ctype = part.get_content_type()
|
||||
print (ctype)
|
||||
if ctype.startswith("text/plain"):
|
||||
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:
|
||||
payload = part.get_payload(decode=True)
|
||||
if payload is None:
|
||||
continue
|
||||
filename = part.get_filename()
|
||||
mtype = part.get_content_type()
|
||||
ext = filename.split('.')[-1].lower()
|
||||
fh = util.hashfile(bytes(payload))
|
||||
fn = fh + '.' + ext
|
||||
fname = os.path.join(settings.MEDIA_ROOT, fn)
|
||||
if not os.path.exists(fname):
|
||||
with open(fname, 'wb') as f:
|
||||
f.write(payload)
|
||||
tname = os.path.join(settings.MEDIA_ROOT, 'thumb-{}.jpg'.format(fn))
|
||||
placeholder = os.path.join(settings.ASSETS_ROOT, 'placeholder.jpg')
|
||||
if not os.path.exists(tname):
|
||||
thumbnail.generate(fname, tname, placeholder)
|
||||
|
||||
att = Attachment(filehash=fh)
|
||||
att.mimetype = mtype
|
||||
att.filename = filename
|
||||
att.save()
|
||||
atts.append(att)
|
||||
post.message = m
|
||||
post.save()
|
||||
|
||||
|
||||
for att in atts:
|
||||
if post.has_attachment(att.filehash):
|
||||
continue
|
||||
post.attachments.add(att)
|
||||
|
||||
|
||||
op, _ = Post.objects.get_or_create(defaults={
|
||||
'posthash': util.hashid(opmsgid),
|
||||
'reference': '',
|
||||
'posted': 0,
|
||||
'last_bumped': 0,
|
||||
'name': 'OP',
|
||||
'subject': 'OP Not Found',
|
||||
'newsgroup': group}, msgid=opmsgid)
|
||||
if bump:
|
||||
op.bump(post.posted)
|
||||
op.save()
|
||||
|
||||
|
Reference in New Issue
Block a user