make mod backend work
This commit is contained in:
parent
9f7de85a1f
commit
d1a81f319d
@ -4,6 +4,9 @@ import base64
|
|||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import nacl.signing
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import time
|
import time
|
||||||
import string
|
import string
|
||||||
@ -29,7 +32,7 @@ def msgid_valid(msgid):
|
|||||||
return re.match("<[a-zA-Z0-9\$\._\-\|]+@[a-zA-Z0-9\$\._\-\|]+>$", msgid) is not None
|
return re.match("<[a-zA-Z0-9\$\._\-\|]+@[a-zA-Z0-9\$\._\-\|]+>$", msgid) is not None
|
||||||
|
|
||||||
def time_int(dtime):
|
def time_int(dtime):
|
||||||
return time.mktime(dtime.timetuple())
|
return int(time.mktime(dtime.timetuple()))
|
||||||
|
|
||||||
def randstr(l, base=string.digits):
|
def randstr(l, base=string.digits):
|
||||||
r = ''
|
r = ''
|
||||||
@ -39,22 +42,28 @@ def randstr(l, base=string.digits):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def createPost(newsgroup, ref, form, files):
|
def createPost(newsgroup, ref, form, files, secretKey=None):
|
||||||
"""
|
"""
|
||||||
create a post and post it to a news server
|
create a post and post it to a news server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
msg = email.message.Message()
|
msg = email.message.Message()
|
||||||
msg['Content-Type'] = 'multipart/mixed'
|
if 'subject' in form:
|
||||||
msg["Subject"] = form["subject"] or "None"
|
msg["Subject"] = form["subject"] or "None"
|
||||||
|
else:
|
||||||
|
msg["Subject"] = "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:
|
if ref:
|
||||||
msg["References"] = ref
|
msg["References"] = ref
|
||||||
msg["Newsgroups"] = newsgroup
|
msg["Newsgroups"] = newsgroup
|
||||||
msg["From"] = '{} <anon@django.nntpchan.tld>'.format(form['name'] or 'Anonymous')
|
name = "Anonymous"
|
||||||
|
if 'name' in form:
|
||||||
|
name = form['name'] or name
|
||||||
|
msg["From"] = '{} <anon@django.nntpchan.tld>'.format(name)
|
||||||
if 'attachment' in files:
|
if 'attachment' in files:
|
||||||
|
msg['Content-Type'] = 'multipart/mixed'
|
||||||
f = files['attachment']
|
f = files['attachment']
|
||||||
part = email.message.Message()
|
part = email.message.Message()
|
||||||
part['Content-Type'] = f.content_type
|
part['Content-Type'] = f.content_type
|
||||||
@ -67,15 +76,45 @@ def createPost(newsgroup, ref, form, files):
|
|||||||
text.set_payload(m)
|
text.set_payload(m)
|
||||||
text['Content-Type'] = 'text/plain'
|
text['Content-Type'] = 'text/plain'
|
||||||
msg.attach(text)
|
msg.attach(text)
|
||||||
|
else:
|
||||||
|
msg['Content-Type'] = 'text/plain; charset=UTF-8'
|
||||||
|
m = '{}'.format(form['message'] or ' ')
|
||||||
|
msg.set_payload(m)
|
||||||
|
msg['Message-Id'] = '<{}${}@signed.{}>'.format(randstr(5), int(time_int(datetime.now())), settings.FRONTEND_NAME)
|
||||||
|
if secretKey:
|
||||||
|
msg['Path'] = settings.FRONTEND_NAME
|
||||||
|
# sign
|
||||||
|
keypair = nacl.signing.SigningKey(secretKey, nacl.signing.encoding.HexEncoder)
|
||||||
|
pubkey = hexlify(keypair.verify_key.encode()).decode('ascii')
|
||||||
|
outerMsg = email.message.Message()
|
||||||
|
h = hashlib.sha512()
|
||||||
|
body = msg.as_bytes()
|
||||||
|
h.update(body)
|
||||||
|
sig = hexlify(keypair.sign(h.digest()).signature).decode('ascii')
|
||||||
|
data = '''Content-Type: message/rfc822; charset=UTF-8
|
||||||
|
Message-ID: {}
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
Newsgroups: {}
|
||||||
|
X-Pubkey-Ed25519: {}
|
||||||
|
X-Signature-Ed25519-Sha512: {}
|
||||||
|
From: {}
|
||||||
|
Date: {}
|
||||||
|
Subject: {}
|
||||||
|
|
||||||
|
{}'''.format(msg["Message-ID"], newsgroup, pubkey, sig, msg["From"], msg["Date"], msg['Subject'], msg.as_string())
|
||||||
|
data = data.encode('utf-8')
|
||||||
|
else:
|
||||||
|
data = msg.as_bytes()
|
||||||
server = settings.NNTP_SERVER
|
server = settings.NNTP_SERVER
|
||||||
server['readermode'] = True
|
server['readermode'] = True
|
||||||
response = None
|
response = None
|
||||||
try:
|
try:
|
||||||
with nntplib.NNTP(**server) as nntp:
|
with nntplib.NNTP(**server) as nntp:
|
||||||
nntp.login(**settings.NNTP_LOGIN)
|
nntp.login(**settings.NNTP_LOGIN)
|
||||||
response = nntp.post(msg.as_bytes())
|
response = nntp.ihave(msg['Message-ID'], data)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
raise e
|
||||||
return None, 'connection to backend failed, {}'.format(e)
|
return None, 'connection to backend failed, {}'.format(e)
|
||||||
if ref:
|
if ref:
|
||||||
return ref, None
|
return ref, None
|
||||||
|
@ -30,14 +30,38 @@ class Postable:
|
|||||||
"""
|
"""
|
||||||
return None, 'handle_post() not implemented'
|
return None, 'handle_post() not implemented'
|
||||||
|
|
||||||
|
def handle_mod(self, request):
|
||||||
|
"""
|
||||||
|
handle moderation parameters
|
||||||
|
"""
|
||||||
|
if 'modactions' in request.POST:
|
||||||
|
actions = request.POST['modactions'] + '\n'
|
||||||
|
body = ''
|
||||||
|
for line in actions.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if len(line) > 0:
|
||||||
|
body += '{}\n'.format(line)
|
||||||
|
key = None
|
||||||
|
if 'secret' in request.POST:
|
||||||
|
key = request.POST['secret']
|
||||||
|
_, err = util.createPost('ctl', '', {'message': body}, {}, key)
|
||||||
|
return True, err
|
||||||
|
return False, None
|
||||||
|
|
||||||
def post(self, request, **kwargs):
|
def post(self, request, **kwargs):
|
||||||
ctx = {
|
ctx = {
|
||||||
'error' : 'invalid captcha'
|
'error' : 'invalid captcha',
|
||||||
|
'only_mod': False
|
||||||
}
|
}
|
||||||
solution = request.session['captcha']
|
solution = request.session['captcha']
|
||||||
if solution is not None:
|
if solution is not None:
|
||||||
if 'captcha' in request.POST:
|
if 'captcha' in request.POST:
|
||||||
if request.POST['captcha'].lower() == solution.lower():
|
if request.POST['captcha'].lower() == solution.lower():
|
||||||
|
processed, err = self.handle_mod(request)
|
||||||
|
if processed:
|
||||||
|
ctx['error'] = err or 'report made'
|
||||||
|
ctx['msgid'] = ''
|
||||||
|
else:
|
||||||
ctx['msgid'], ctx['error'] = self.handle_post(request, **kwargs)
|
ctx['msgid'], ctx['error'] = self.handle_post(request, **kwargs)
|
||||||
request.session['captcha'] = ''
|
request.session['captcha'] = ''
|
||||||
request.session.save()
|
request.session.save()
|
||||||
@ -61,6 +85,7 @@ class BoardView(generic.View, Postable):
|
|||||||
name = 'overchan.{}'.format(name)
|
name = 'overchan.{}'.format(name)
|
||||||
if not util.newsgroup_valid(name):
|
if not util.newsgroup_valid(name):
|
||||||
return None, "invalid newsgroup: {}".format(name)
|
return None, "invalid newsgroup: {}".format(name)
|
||||||
|
self.handle_mod(request)
|
||||||
return util.createPost(name, None, request.POST, request.FILES)
|
return util.createPost(name, None, request.POST, request.FILES)
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,7 +76,14 @@
|
|||||||
Secret:
|
Secret:
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="password" name="modkey"></input>
|
<input type="password" name="secret"></input>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<button onclick="document.getElementById('postform').submit()">report</button>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
captcha
|
captcha
|
||||||
django
|
django
|
||||||
psycopg2
|
psycopg2
|
||||||
|
pynacl
|
||||||
|
Reference in New Issue
Block a user