[Nym3-commit] r456 - in trunk/nymbaron: . Server
zax at conuropsis.org
zax at conuropsis.org
Wed Mar 8 02:16:11 CET 2006
Author: zax
Date: 2006-03-08 02:16:08 +0100 (Wed, 08 Mar 2006)
New Revision: 456
Modified:
trunk/nymbaron/Mail.py
trunk/nymbaron/Server/Config.py
trunk/nymbaron/Server/Main.py
Log:
Introduce SMTP and Sendmail relaying for outgoing nymholder messages.
- Note: Retabbed for compliance with PEP-8, compare with diff -E
Modified: trunk/nymbaron/Mail.py
===================================================================
--- trunk/nymbaron/Mail.py 2006-03-06 20:49:42 UTC (rev 455)
+++ trunk/nymbaron/Mail.py 2006-03-08 01:16:08 UTC (rev 456)
@@ -1,5 +1,6 @@
# $Id$
# -*- coding: utf-8 -*-
+# vim: tabstop=4 expandtab shiftwidth=4 autoindent
# Copyright (c) 2004,2005 Jean-René Reinhard <jr at komite.net>
# and Laurent Fousse <laurent at komite.net>.
#
@@ -26,12 +27,17 @@
This package contains utilities to process mails."""
-import os
-import tempfile
-import random
import base64
import email.Parser
import nymbaron.Common as Common
+import os
+import random
+import smtplib
+import socket
+import string
+import sys
+import tempfile
+from email.MIMEText import MIMEText
slen = 128
"""The length of a summary in bytes"""
@@ -58,32 +64,32 @@
#TODO assert type(seq) == int?
#TODO: this is not RFC2822-compliant
vheaders = [ 'Cc', 'From', 'Date', 'In-Reply-To', 'Sender',
- 'Message-Id', 'References', 'Return-Path', 'Subject',
- 'To', 'X-Anonymous', 'X-Spam-Level']
+ 'Message-Id', 'References', 'Return-Path', 'Subject',
+ 'To', 'X-Anonymous', 'X-Spam-Level']
par = email.Parser.HeaderParser()
message = par.parsestr(msg)
res = ''
for i in vheaders:
- if i in message:
- res = res + i + ': ' + message[i][0:80] + "\n"
+ if i in message:
+ res = res + i + ': ' + message[i][0:80] + "\n"
l = message.get_all('Received')
if l:
- res = res + 'Received: ' + l[0][0:80] + "\n"
+ res = res + 'Received: ' + l[0][0:80] + "\n"
res = res + 'X-Octets: ' + str(len(msg)) + "\n"
res = res + 'X-Nym-Sequence: ' + str(seq) + "\n"
res = res + "\n"
print res
if not message.is_multipart():
- res = res + message.get_payload()[0:slen]
+ res = res + message.get_payload()[0:slen]
else:
- n = 0
- p = message.get_payload()
- j = 0
- while n < slen and j < len(p):
- s = p[j].as_string(True)[0:slen - n]
- res = res + s
- n = n + len(s)
- j = j + 1
+ n = 0
+ p = message.get_payload()
+ j = 0
+ while n < slen and j < len(p):
+ s = p[j].as_string(True)[0:slen - n]
+ res = res + s
+ n = n + len(s)
+ j = j + 1
return res
def syn_summary(synopsis):
@@ -94,11 +100,11 @@
summary_headers = ['From', 'Subject', 'Date']
res = ""
for header in summary_headers:
- if syn[header] == None:
- syn[header] = ""
- res = res + header + ': ' + syn[header] + '\n'
+ if syn[header] == None:
+ syn[header] = ""
+ res = res + header + ': ' + syn[header] + '\n'
if len(res):
- res = res[:-1]
+ res = res[:-1]
return res
def XNymSeq(synopsis):
@@ -109,7 +115,7 @@
syn = par.parsestr(synopsis)
seq = syn['X-Nym-Sequence']
if seq == None:
- raise SeqNotFound()
+ raise SeqNotFound()
return int(seq)
def tmpFileMsg(body):
@@ -130,13 +136,13 @@
r1 = 0
offset = 0
for i in l[:8]:
- if i: r1 |= (1 << offset)
- offset += 1
+ if i: r1 |= (1 << offset)
+ offset += 1
r2 = 0
offset = 0
for i in l[8:]:
- if i: r2 |= (1 << offset)
- offset += 1
+ if i: r2 |= (1 << offset)
+ offset += 1
return chr(r2) + chr(r1)
def bf2list(bf):
@@ -145,9 +151,9 @@
assert (len(bf) == 2 and type(bf) == str)
l = []
for i in range(2):
- for j in range(8):
- if ord(bf[i]) & (1 << j):
- l.append((1 - i) * 8 + j)
+ for j in range(8):
+ if ord(bf[i]) & (1 << j):
+ l.append((1 - i) * 8 + j)
return l
def b2s(c):
@@ -160,27 +166,73 @@
par = email.Parser.HeaderParser()
message = par.parsestr(msg)
for h in forbidden_headers:
- if message.has_key(h):
- del message[h]
+ if message.has_key(h):
+ del message[h]
return message.as_string()
def relay(nym, rt, ri, sname, body):
+ #TODO: This function is unused at this time and can probably be removed
"""relay the e-mail in body according to the routing type rt
and the routing info ri for the nymholder of nym"""
body = filter_header(body)
b = 'From: ' + nym + '@' + sname + "\n\n" + body
fname = tmpFileMsg(b) #TODO we can avoid the tempfile with some fd manipultation : exec mixminion, write b in its stdin
- relaycmd = "mixminion send -t 0x" + b2s(rt[0]) + b2s(rt[1]) + ":" + ri + " -i " + fname
- return relaycmd
+ mixcmd = "mixminion send -t 0x" + b2s(rt[0]) + b2s(rt[1]) + ":" + ri + " -i " + fname
+ print mixcmd
+ ec = os.system(mixcmd)
+ # TODO : debugging cruft
+ #os.unlink(fname)
+ print "Raw relayed message left in " + fname
+ return ec
+def relay_prep(nym, you, sname, body, abuse):
+ """Format a message as a single string that can be passed
+ to various rfc822 compliant email routines"""
+
+ # Make a From header and include the nymholder as a real_name.
+ fromhdr = '%s <%s@%s>' % (nym,nym,sname)
+
+ msg = MIMEText(body)
+ msg['From'] = fromhdr
+ msg['To'] = you
+ # TODO Headers such as Subject, References etc. need to be read from
+ # either config or from the incoming relay message.
+ msg['Subject'] = 'Type-III Pseudonym Message'
+ if abuse:
+ msg['X-Abuse-Contact'] = abuse
+ return msg.as_string()
+
+def relay_smtp(nym, you, sname, payload, timeout, smtphost):
+ """ Relay an email message through Python's internal
+ smtplib library."""
+ socket.setdefaulttimeout(timeout)
+ me = nym + '@' + sname
+ # Send the message to the designated smtp server
+ # TODO Need some error handling when logging gets enabled
+ mailserver = smtplib.SMTP(smtphost)
+ #mailserver.set_debuglevel(1)
+ mailserver.sendmail(me, [you], payload)
+ mailserver.quit()
+
+def relay_sendmail(payload, sm):
+ """ Depreciated in favour of using Python smtplib, but this
+ works fine on systems with sendmail"""
+ # TODO Need some error handling when logging gets enabled
+ p = os.popen("%s -t" % sm, "w")
+ p.write(payload)
+ status = p.close()
+ if status:
+ print "Sendmail failed with status", status
+ sys.exit(2)
+
def genMid(length = midLen):
"""Randomly generates a mid of given length different from oldestMid"""
ret = oldestMid
while ret == oldestMid:
- res = ""
- for _ in range(0, length):
+ res = ""
+ for _ in range(0, length):
res = res + chr(random.randint(0, 255))
- ret = res
+ ret = res
return ret
def mid2filename(mid):
Modified: trunk/nymbaron/Server/Config.py
===================================================================
--- trunk/nymbaron/Server/Config.py 2006-03-06 20:49:42 UTC (rev 455)
+++ trunk/nymbaron/Server/Config.py 2006-03-08 01:16:08 UTC (rev 456)
@@ -1,5 +1,6 @@
# $Id$
# -*- coding: utf-8 -*-
+# vim: tabstop=4 expandtab shiftwidth=4 autoindent
#
# Copyright (c) 2004,2005 Jean-René Reinhard <jr at komite.net>
# and Laurent Fousse <laurent at komite.net>.
@@ -32,77 +33,107 @@
def userfile():
if os.environ.has_key('HOME'):
- return os.environ['HOME'] + '/.nymbaronrc'
+ return os.environ['HOME'] + '/.nymbaronrc'
else:
- import pwd
- return pwd.getpwuid(os.getuid())[5] + '/.nymbaronrc'
+ import pwd
+ return pwd.getpwuid(os.getuid())[5] + '/.nymbaronrc'
def string2loglevel(s):
s = s.lower()
if s == 'debug':
- return logging.DEBUG
+ return logging.DEBUG
if s == 'info':
- return logging.INFO
+ return logging.INFO
return logging.DEBUG
class Config:
def __init__(self, filename = None):
- self.DEBUG = False
- """Whether the server erases the messages it generates from tmp"""
+ self.DEBUG = False
+ """Whether the server erases the messages it generates from tmp"""
- self.online = True
- """Whether the server sends the messages it generates on the mixminion
- network"""
+ self.online = True
+ """Whether the server sends the messages it generates on the mixminion
+ network"""
- self.serverName = 'nymserv.komite.net'
- """The hostname of the host on which the nymserver is running."""
+ self.serverName = 'nymserv.komite.net'
+ """The hostname of the host on which the nymserver is running."""
- self.path = '/tmp'
- """The path to the directory containing the server data"""
+ self.path = '/tmp'
+ """The path to the directory containing the server data"""
- self.logfile = '/var/tmp/nymbaron.log'
- """The file where logging informations are written"""
+ self.logfile = '/var/tmp/nymbaron.log'
+ """The file where logging informations are written"""
- self.loglevel = logging.DEBUG
- """The logging verbosity"""
+ self.loglevel = logging.DEBUG
+ """The logging verbosity"""
- self.default_settings = { 'quota' : 10 * 2**20, 'usage' : 0,
- 'idKey' : None, 'encKey' : None, 'policy' : None,
- 'SendMsgAfter' : 24, 'SendSummaryAfter' : 12,
- 'MaxSURBsPerDay' : 10, 'EncryptSummaryAfter' : 24,
- 'HoldUntilAck' : 'always', 'ShutdownPhrase' : None,
- 'HoldSURBs' : 5, 'nSurbs' : 0, 'up' : False,
- 'cr' : "", 'inidgst' : "" }
- """The default settings of a user account."""
+ self.relay_method = 'smtp'
+ """ The method for relaying email to a non-anonymous recipient.
+ Currently 'smtp' or 'sendmail' are supported."""
- self.setupscript = None
- """The path to a script to execute upon successful new account
- creation"""
-
- if filename:
- config = ConfigParser.RawConfigParser()
- config.read(filename)
-
- if config.has_section('general'):
- if config.has_option('general', 'online'):
- self.online = config.getboolean('general', 'online')
- if config.has_option('general', 'DEBUG'):
- self.DEBUG = config.getboolean('general', 'DEBUG')
- if config.has_option('general', 'path'):
- self.path = config.get('general', 'path')
- if config.has_option('general', 'serverName'):
- self.serverName = config.get('general', 'serverName')
- if config.has_option('general', 'setupscript'):
- self.setupscript = config.get('general', 'setupscript')
+ self.abuse_address = ''
+ """ The address that will be included in a X-Abuse-Contact header
+ on outgoing relay messages"""
- if config.has_section('accounts'):
- for k in self.default_settings.keys():
- if config.has_option('accounts', k):
- self.default_settings[k] = config.get('accounts', k)
+ self.sendmail_path = '/usr/sbin/sendmail'
+ """ Path to the sendmail program. This is used if relay_method is
+ set to sendmail."""
- if config.has_section('logging'):
- if config.has_option('logging', 'logfile'):
- self.logfile = config.get('logging', 'logfile')
- if config.has_option('logging', 'loglevel'):
- self.loglevel = string2loglevel(config.get('logging', 'loglevel'))
+ self.timeout = 10
+ """ Seconds to wait before smtp socket timeout."""
+
+ self.smtphost = 'localhost'
+ """ SMTP host to relay messages through."""
+
+ self.default_settings = { 'quota' : 10 * 2**20, 'usage' : 0,
+ 'idKey' : None, 'encKey' : None, 'policy' : None,
+ 'SendMsgAfter' : 24, 'SendSummaryAfter' : 12,
+ 'MaxSURBsPerDay' : 10, 'EncryptSummaryAfter' : 24,
+ 'HoldUntilAck' : 'always', 'ShutdownPhrase' : None,
+ 'HoldSURBs' : 5, 'nSurbs' : 0, 'up' : False,
+ 'cr' : "", 'inidgst' : "" }
+ """The default settings of a user account."""
+
+ self.setupscript = None
+ """The path to a script to execute upon successful new account
+ creation"""
+
+ if filename:
+ config = ConfigParser.RawConfigParser()
+ config.read(filename)
+
+ if config.has_section('general'):
+ if config.has_option('general', 'online'):
+ self.online = config.getboolean('general', 'online')
+ if config.has_option('general', 'DEBUG'):
+ self.DEBUG = config.getboolean('general', 'DEBUG')
+ if config.has_option('general', 'path'):
+ self.path = config.get('general', 'path')
+ if config.has_option('general', 'serverName'):
+ self.serverName = config.get('general', 'serverName')
+ if config.has_option('general', 'setupscript'):
+ self.setupscript = config.get('general', 'setupscript')
+
+ if config.has_section('accounts'):
+ for k in self.default_settings.keys():
+ if config.has_option('accounts', k):
+ self.default_settings[k] = config.get('accounts', k)
+
+ if config.has_section('logging'):
+ if config.has_option('logging', 'logfile'):
+ self.logfile = config.get('logging', 'logfile')
+ if config.has_option('logging', 'loglevel'):
+ self.loglevel = string2loglevel(config.get('logging', 'loglevel'))
+
+ if config.has_section('relay'):
+ if config.has_option('relay', 'relay_method'):
+ self.relay_method = config.get('relay', 'relay_method')
+ if config.has_option('relay', 'abuse_address'):
+ self.abuse_address = config.get('relay', 'abuse_address')
+ if config.has_option('relay', 'sendmail_path'):
+ self.sendmail_path = config.get('relay', 'sendmail_path')
+ if config.has_option('relay', 'timeout'):
+ self.timeout = config.getfloat('relay', 'timeout')
+ if config.has_option('relay', 'smtphost'):
+ self.smtphost = config.get('relay', 'smtphost')
Modified: trunk/nymbaron/Server/Main.py
===================================================================
--- trunk/nymbaron/Server/Main.py 2006-03-06 20:49:42 UTC (rev 455)
+++ trunk/nymbaron/Server/Main.py 2006-03-08 01:16:08 UTC (rev 456)
@@ -1,6 +1,7 @@
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
# $Id$
+# vim: tabstop=4 expandtab shiftwidth=4 autoindent
#
# Copyright (c) 2004,2005 Jean-René Reinhard <jr at komite.net>
# and Laurent Fousse <laurent at komite.net>.
@@ -58,19 +59,19 @@
def readMessage(filename):
if filename:
- try:
- f = open(filename, "r")
- msg = f.read()
- f.close()
- except IOError:
- logger.error("Can't read incoming message in specified file %s" % filename)
- sys.exit(1)
+ try:
+ f = open(filename, "r")
+ msg = f.read()
+ f.close()
+ except IOError:
+ logger.error("Can't read incoming message in specified file %s" % filename)
+ sys.exit(1)
else:
- try:
- msg = sys.stdin.read()
- except KeyboardInterrupt:
- logger.error("Interrupted by the user while reading incoming message from stdin")
- sys.exit(2)
+ try:
+ msg = sys.stdin.read()
+ except KeyboardInterrupt:
+ logger.error("Interrupted by the user while reading incoming message from stdin")
+ sys.exit(2)
return msg
def load_config():
@@ -91,13 +92,13 @@
fun is: fun(account[, tuple of arguments specific to fun]), returns nothing
"""
for f in os.listdir(config.path):
- if len(f) >= 4 and f[-4:] == ".dat":
- username = f[:-4]
- nymuser = User.User(username, config)
- if funargs:
- fun(nymuser, *funargs)
- else:
- fun(nymuser)
+ if len(f) >= 4 and f[-4:] == ".dat":
+ username = f[:-4]
+ nymuser = User.User(username, config)
+ if funargs:
+ fun(nymuser, *funargs)
+ else:
+ fun(nymuser)
def processIncoming(localpart, msg):
"""Process incoming mail from the MTA
@@ -105,15 +106,15 @@
- checks whether the new mail violates its quota
- finally stores the message """
try:
- nymuser = User.User(localpart, config)
+ nymuser = User.User(localpart, config)
except User.NoSuchUser:
- logger.error("No such user %s while processing incoming email" % localpart)
- sys.exit(73)
+ logger.error("No such user %s while processing incoming email" % localpart)
+ sys.exit(73)
# TODO : we should honor the "Quota" sending policy.
if nymuser.usage() + len(msg) > nymuser.quota():
- logger.error("Quota exceeded for user %s : %s > %s" % (localpart, repr(nymuser.usage()),
- repr(nymuser.quota())))
- sys.exit(75)
+ logger.error("Quota exceeded for user %s : %s > %s" % (localpart, repr(nymuser.usage()),
+ repr(nymuser.quota())))
+ sys.exit(75)
# Valid user, not over quota. Filtering policy can wait.
nymuser.store(msg)
sys.exit(0)
@@ -129,198 +130,208 @@
logger.debug("Processing control message:\n%s" % base64.encodestring(msg))
sr = Message.StrReader(msg)
try:
- h = sr.readHeader()
- if (h.nym == ""):
- comList = sr.readCommandCToSList()
- try:
- if (len(comList) != 3):
- raise MyException()
- #this may be an account setup message
- #we suppose there is a exactly 1 Create Command in the message,
- # 1 Newpk, and 1 surb. more will raise an error
+ h = sr.readHeader()
+ if (h.nym == ""):
+ comList = sr.readCommandCToSList()
+ try:
+ if (len(comList) != 3):
+ raise MyException()
+ #this may be an account setup message
+ #we suppose there is a exactly 1 Create Command in the message,
+ # 1 Newpk, and 1 surb. more will raise an error
- nymUser = None
- mdgst = _cr.sha1(msg)
- #phase 1 we look for the command create
- for idx, com in enumerate(comList):
- if(com.ct() == 0): # TODO : evil numeric litteral
- #the Create command
- for pnym in com.list:
- try:
- nymUser = User.User(pnym, config, 1)
- except User.AlreadySuchUser:
- #a nym pnym has been created : check it
- #doesn't relate to the creat being processed
- nymUser = User.User(pnym, config, 0)
- if nymUser['inidgst'] == mdgst:
- #it does: we resend the challenge
- #and quit
- nymUser.received(h.seqNo)
- created = Message.Created()
- created.fromData(nymUser.username,
- nymUser['cr'])
- nymUser.advanced_send(
- Message.buildMessage([created]))
- return
- else:
- #it doesn't: we clean and continue
- del nymUser
- nymUser = None
- if nymUser != None:
- break
- if (nymUser == None):
- #TODO send an Error message to the client when surbs become available?
- #for the time being just ignore
- logger.info("All nyms proposed in the list were already attributed")
- raise MyException()
- del comList[idx]
- break
- if (nymUser == None):
- #TODO send an Error message to the client when surbs become available?
- #for the time being just ignore
- logger.info("No Create Command")
- raise MyException()
-
- #phase 2 we look for the command surb
- for idx, com in enumerate(comList):
- if(com.ct()==2): # TODO : evil numeric litteral
- nymUser.addSurbs(com.surbs)
- if nymUser['nSurbs'] < 3:
- logger.info("Not Enough Surbs")
- raise MyException()
- del comList[idx]
- break
- if(len(comList) != 1):
- nymUser.abort()
- raise MyException()
- #phase 3 the last command should be a Newpk
- com = comList[0]
- if(com.ct() != 3): # TODO : evil numeric litteral
- nymUser.abort()
- raise MyException()
- nymUser.setKeys(com.ekid, com.ekenc)
- if(not nymUser.checkMessageSign(msg[Message.sigLength:],h.sig)):
- nymUser.abort()
- raise MyException()
- else: # Valid account creation request. Send CREATED
- #remember we received this register request
- nymUser['inidgst'] = mdgst
- nymUser.received(h.seqNo)
- #we forget about CREATE2 message and consider the account as
- #up
- nymUser.setUp()
- #send back the challenge
- created = Message.Created()
- #TODO non empty challenge?
- created.fromData(nymUser.username, "")
- nymUser.advanced_send(Message.buildMessage([created]))
- except MyException:
- #if you come here something went wrong during the account
- #initialization
- logger.debug("Bad formed account creation message")
- sys.exit(2) #TODO smart error code
- else: # NYM is not empty
- try:
- nymUser = User.User(h.nym, config)
- except User.NoSuchUser:
- logger.debug("No such user %s" % h.nym)
- sys.exit(73) #TODO is it the smart error code
- if(not nymUser.checkMessageSign(msg[Message.sigLength:],h.sig)):
- return
- #The message comes from a known nick and is authenticated
- #register the seqNo as received
- #TODO is it ok?
- nymUser.received(h.seqNo)
- comList = sr.readCommandCToSList()
- for com in comList:
- if (com.ct() == Message.CToSCODE['Create']):
- #we ignore the Create command if it comes from the nymholder of an account, should we rise an error?
- pass
- #if the account is not initialized, or if it is already up we ignore Create2 messages
- elif (com.ct() == Message.CToSCODE['Create2']):
- #for the time being we forget about CREATE2 messages
- pass
- #if not nymUser.isUp():
- # if(nymUser.checkChallenge(com.cr)):
- # nymUser.setUp()
- #other commands are only taken into account if the account is up
- elif (nymUser.isUp()):
- if (com.ct() == Message.CToSCODE['Surb']):
- if (len(com.surbs) == 0):
- nymUser.delSurbs()
- else:
- nymUser.addSurbs(com.surbs)
- elif (com.ct() == Message.CToSCODE['Newpk']):
- nymUser.setKeys(com.kid,com.kenc)
- elif (com.ct() == Message.CToSCODE['Relay']):
- relaycmd = Mail.relay(h.nym, com.rt, com.ri,
- config.serverName, com.body)
- logger.debug('Attempting to relay nymholder message using command %s' % relaycmd)
- ec = os.system(relaycmd)
- if (ec == 0):
- logger.debug('Message relay successfully processed')
- else:
- logger.error("mixminion exited abnormally with error code %d" % ec)
- sys.exit(2)
-
- elif (com.ct() == Message.CToSCODE['Get']):
- msgList = []
- sendList = []
- for m in com.l:
- if nymUser.hasMail(m):
- msgCom = Message.Msg()
- msgCom.fromData(m,nymUser.getMail(m))
- msgList.append(msgCom)
- sendList.append(m)
- ec = nymUser.advanced_send(
- Message.buildMessage(msgList))
- logger.debug("EC is " + str(ec))
- if (ec == 0):
- nymUser.markMid(sendList,lifeCycle['sent-in-full'])
- if(nymUser['HoldUntilAck'] == 'never'):
- map(nymUser.delete_msg,sendList)
-
- else:
- logger.error("mixminion exited abnormally with error code %d" % ec)
- sys.exit(2)
-
- elif (com.ct() == Message.CToSCODE['Summarize']):
- comList = []
- sendList = nymUser.prepareSummary(com.num, com.after)
- mList = []
- if sendList:
- for (ml, bf, blob) in sendList:
- sumCom = Message.Summary()
- sumCom.fromData(bf, blob)
- comList.append(sumCom)
- mList = mList + ml
- else:
- sumCom = Message.Summary()
- sumCom.fromData("\x00\x00","")
- comList = [sumCom]
- ec = nymUser.send(Message.buildMessage(comList))
- if (ec == 0):
- nymUser.markMid(mList, lifeCycle['synopsis-sent'])
- else:
- logger.error("mixminion exited abnormally with error code %d" % ec)
- sys.exit(2)
+ nymUser = None
+ mdgst = _cr.sha1(msg)
+ #phase 1 we look for the command create
+ for idx, com in enumerate(comList):
+ if(com.ct() == 0): # TODO : evil numeric litteral
+ #the Create command
+ for pnym in com.list:
+ try:
+ nymUser = User.User(pnym, config, 1)
+ except User.AlreadySuchUser:
+ #a nym pnym has been created : check it
+ #doesn't relate to the creat being processed
+ nymUser = User.User(pnym, config, 0)
+ if nymUser['inidgst'] == mdgst:
+ #it does: we resend the challenge
+ #and quit
+ nymUser.received(h.seqNo)
+ created = Message.Created()
+ created.fromData(nymUser.username,
+ nymUser['cr'])
+ nymUser.advanced_send(
+ Message.buildMessage([created]))
+ return
+ else:
+ #it doesn't: we clean and continue
+ del nymUser
+ nymUser = None
+ if nymUser != None:
+ break
+ if (nymUser == None):
+ #TODO send an Error message to the client when surbs become available?
+ #for the time being just ignore
+ logger.info("All nyms proposed in the list were already attributed")
+ raise MyException()
+ del comList[idx]
+ break
+ if (nymUser == None):
+ #TODO send an Error message to the client when surbs become available?
+ #for the time being just ignore
+ logger.info("No Create Command")
+ raise MyException()
+
+ #phase 2 we look for the command surb
+ for idx, com in enumerate(comList):
+ if(com.ct()==2): # TODO : evil numeric litteral
+ nymUser.addSurbs(com.surbs)
+ if nymUser['nSurbs'] < 3:
+ logger.info("Not Enough Surbs")
+ raise MyException()
+ del comList[idx]
+ break
+ if(len(comList) != 1):
+ nymUser.abort()
+ raise MyException()
+ #phase 3 the last command should be a Newpk
+ com = comList[0]
+ if(com.ct() != 3): # TODO : evil numeric litteral
+ nymUser.abort()
+ raise MyException()
+ nymUser.setKeys(com.ekid, com.ekenc)
+ if(not nymUser.checkMessageSign(msg[Message.sigLength:],h.sig)):
+ nymUser.abort()
+ raise MyException()
+ else: # Valid account creation request. Send CREATED
+ #remember we received this register request
+ nymUser['inidgst'] = mdgst
+ nymUser.received(h.seqNo)
+ #we forget about CREATE2 message and consider the account as
+ #up
+ nymUser.setUp()
+ #send back the challenge
+ created = Message.Created()
+ #TODO non empty challenge?
+ created.fromData(nymUser.username, "")
+ nymUser.advanced_send(Message.buildMessage([created]))
+ except MyException:
+ #if you come here something went wrong during the account
+ #initialization
+ logger.debug("Bad formed account creation message")
+ sys.exit(2) #TODO smart error code
+ else: # NYM is not empty
+ try:
+ nymUser = User.User(h.nym, config)
+ except User.NoSuchUser:
+ logger.debug("No such user %s" % h.nym)
+ sys.exit(73) #TODO is it the smart error code
+ if(not nymUser.checkMessageSign(msg[Message.sigLength:],h.sig)):
+ return
+ #The message comes from a known nick and is authenticated
+ #register the seqNo as received
+ #TODO is it ok?
+ nymUser.received(h.seqNo)
+ comList = sr.readCommandCToSList()
+ for com in comList:
+ if (com.ct() == Message.CToSCODE['Create']):
+ #we ignore the Create command if it comes from the nymholder of an account, should we rise an error?
+ pass
+ #if the account is not initialized, or if it is already up we ignore Create2 messages
+ elif (com.ct() == Message.CToSCODE['Create2']):
+ #for the time being we forget about CREATE2 messages
+ pass
+ #if not nymUser.isUp():
+ # if(nymUser.checkChallenge(com.cr)):
+ # nymUser.setUp()
+ #other commands are only taken into account if the account is up
+ elif (nymUser.isUp()):
+ if (com.ct() == Message.CToSCODE['Surb']):
+ if (len(com.surbs) == 0):
+ nymUser.delSurbs()
+ else:
+ nymUser.addSurbs(com.surbs)
+ elif (com.ct() == Message.CToSCODE['Newpk']):
+ nymUser.setKeys(com.kid,com.kenc)
+ elif (com.ct() == Message.CToSCODE['Relay']):
+# ec = Mail.relay(h.nym, com.rt, com.ri,
+# config.serverName, com.body)
+# if (ec != 0):
+# logger.error("mixminion exited abnormally with error code %d" % ec)
+# sys.exit(2)
- elif (com.ct() == Message.CToSCODE['Delete']):
- for mid in com.l:
- nymUser.delete_msg(mid)
- elif (com.ct() == Message.CToSCODE['Policy']):
- if(com.opt in Common.userPolicy):
- nymUser[com.opt] = com.val
- else:
- pass
+ #TODO: Passing this many args is messy. Perhaps they should be
+ # written to a dictionary and passed as one?
+ payload = Mail.relay_prep(h.nym, com.ri, config.serverName, com.body,
+ config.abuse_address)
+ if config.relay_method == 'smtp':
+ Mail.relay_smtp(h.nym, com.ri, config.serverName, payload,
+ config.timeout, config.smtphost)
+ elif config.relay_method == 'sendmail':
+ Mail.relay_sendmail(payload, config.sendmail_path)
+ else:
+ logger.error('Unsupported relay option %s specified' % config.relay_method)
+ sys.exit(2)
+
+
+ elif (com.ct() == Message.CToSCODE['Get']):
+ msgList = []
+ sendList = []
+ for m in com.l:
+ if nymUser.hasMail(m):
+ msgCom = Message.Msg()
+ msgCom.fromData(m,nymUser.getMail(m))
+ msgList.append(msgCom)
+ sendList.append(m)
+ ec = nymUser.advanced_send(
+ Message.buildMessage(msgList))
+ logger.debug("EC is " + str(ec))
+ if (ec == 0):
+ nymUser.markMid(sendList,lifeCycle['sent-in-full'])
+ if(nymUser['HoldUntilAck'] == 'never'):
+ map(nymUser.delete_msg,sendList)
+
+ else:
+ logger.error("mixminion exited abnormally with error code %d" % ec)
+ sys.exit(2)
+
+ elif (com.ct() == Message.CToSCODE['Summarize']):
+ comList = []
+ sendList = nymUser.prepareSummary(com.num, com.after)
+ mList = []
+ if sendList:
+ for (ml, bf, blob) in sendList:
+ sumCom = Message.Summary()
+ sumCom.fromData(bf, blob)
+ comList.append(sumCom)
+ mList = mList + ml
+ else:
+ sumCom = Message.Summary()
+ sumCom.fromData("\x00\x00","")
+ comList = [sumCom]
+ ec = nymUser.send(Message.buildMessage(comList))
+ if (ec == 0):
+ nymUser.markMid(mList, lifeCycle['synopsis-sent'])
+ else:
+ logger.error("mixminion exited abnormally with error code %d" % ec)
+ sys.exit(2)
+
+ elif (com.ct() == Message.CToSCODE['Delete']):
+ for mid in com.l:
+ nymUser.delete_msg(mid)
+ elif (com.ct() == Message.CToSCODE['Policy']):
+ if(com.opt in Common.userPolicy):
+ nymUser[com.opt] = com.val
+ else:
+ pass
except Message.ParseError, inst:
- logger.error("Parse error in incoming control message %s" % str(inst))
- sys.exit(2) #TODO error code
-
+ logger.error("Parse error in incoming control message %s" % str(inst))
+ sys.exit(2) #TODO error code
+
def main(args):
if len(args) < 2:
- print usage_string
- sys.exit(1)
+ print usage_string
+ sys.exit(1)
# Try to load the configuration file.
load_config()
# The main logger object :
@@ -333,52 +344,52 @@
logger.setLevel(config.loglevel)
if args[1] == "deliver":
- parser = OptionParser(usage =
- """nymbarond deliver [options]
- Deliver a message to a nym account.""")
- parser.add_option("-n", "--nym", action = "store", dest = "nym",
- help = "The nym to which deliver the message")
- parser.add_option("-f", "--file", action = "store",
- dest = "file", help = "The file to read the message " +
- "from, or stdin if omitted")
- (options, args) = parser.parse_args(args[2:])
- if not options.nym:
- print ("You must provide a nym to which the message is adressed")
- sys.exit(1)
- processIncoming(options.nym, readMessage(options.file))
- sys.exit(0)
+ parser = OptionParser(usage =
+ """nymbarond deliver [options]
+ Deliver a message to a nym account.""")
+ parser.add_option("-n", "--nym", action = "store", dest = "nym",
+ help = "The nym to which deliver the message")
+ parser.add_option("-f", "--file", action = "store",
+ dest = "file", help = "The file to read the message " +
+ "from, or stdin if omitted")
+ (options, args) = parser.parse_args(args[2:])
+ if not options.nym:
+ print ("You must provide a nym to which the message is adressed")
+ sys.exit(1)
+ processIncoming(options.nym, readMessage(options.file))
+ sys.exit(0)
if args[1] == "process":
- parser = OptionParser(usage =
- """nymbarond process [options]
- Process a command message.""")
- parser.add_option("-f", "--file", action = "store",
- dest = "file", help = "The file to read the message " +
- "from, or stdin if omitted")
- (options, args) = parser.parse_args(args[2:])
- logger.debug("Got an incoming control message")
- try:
- msg = readMessage(options.file)
- processMessage(msg)
- except Exception: #TODO catch a more detailed exception
- # see if we got a base64 encoded message.
- m = re.search("binary\\n\\n(.*)\\n---", msg, re.S)
- if m:
- processMessage(base64.decodestring(m.group(1)))
- else:
- sys.stderr.write("Unable to find valid control message")
- sys.exit(0)
+ parser = OptionParser(usage =
+ """nymbarond process [options]
+ Process a command message.""")
+ parser.add_option("-f", "--file", action = "store",
+ dest = "file", help = "The file to read the message " +
+ "from, or stdin if omitted")
+ (options, args) = parser.parse_args(args[2:])
+ logger.debug("Got an incoming control message")
+ try:
+ msg = readMessage(options.file)
+ processMessage(msg)
+ except Exception: #TODO catch a more detailed exception
+ # see if we got a base64 encoded message.
+ m = re.search("binary\\n\\n(.*)\\n---", msg, re.S)
+ if m:
+ processMessage(base64.decodestring(m.group(1)))
+ else:
+ sys.stderr.write("Unable to find valid control message")
+ sys.exit(0)
if args[1] == "clean-surbs":
- mapAccount(User.User.clean_surbs)
- sys.exit(0)
+ mapAccount(User.User.clean_surbs)
+ sys.exit(0)
if args[1] == "encode-synopses":
sys.exit(0)
if args[1] == "help":
- print usage_string
- sys.exit(0)
+ print usage_string
+ sys.exit(0)
# Unknown command
sys.stderr.write("Error: unknown command \"" + args[1] + "\"\n")
sys.exit(1)
More information about the Nym3-commit
mailing list