| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import os |
| import sys |
| import cgi |
| import tempfile |
| import syslog |
| import smtplib |
| import re |
| from ConfigParser import SafeConfigParser |
| |
| from email import Header, Utils |
| try: |
| from email.mime.text import MIMEText |
| except ImportError: |
| from email.MIMEText import MIMEText |
| |
| import hashlib |
| sha1_constructor = hashlib.sha1 |
| |
| |
| CONFIG = '/etc/lookaside.cfg' |
| conf = SafeConfigParser() |
| conf.read(CONFIG) |
| |
| |
| BUFFER_SIZE = 4096 |
| |
| |
| SECTION = re.compile(r'\[(.+)\]') |
| OPTION = re.compile(r'(.+)=(.+)') |
| REPO = re.compile(r'([^/]+).git$') |
| |
| def merge_gitblit_section(repoacl, repos, users): |
| for repo in repos: |
| if repo not in repoacl: |
| repoacl[repo] = [] |
| for user in users: |
| if user not in repoacl[repo]: |
| repoacl[repo].append(user) |
| |
| |
| def parse_gitblit_config(filename): |
| insection = False |
| repoacl = {} |
| sectrepos = [] |
| sectusers = [] |
| |
| f = open(filename) |
| for line in f: |
| if line.strip() == '' or line[0] == '#': |
| continue |
| secth = SECTION.match(line) |
| if secth: |
| if insection: |
| merge_gitblit_section(repoacl, sectrepos, sectusers) |
| |
| sectrepos = [] |
| sectusers = [] |
| else: |
| insection = True |
| continue |
| opt = OPTION.match(line) |
| if opt: |
| if not insection: |
| continue |
| key = opt.group(1).strip() |
| value = opt.group(2).strip() |
| |
| if key == "repository": |
| pack = REPO.search(value) |
| if pack: |
| sectrepos.append(pack.group(1)) |
| elif key == "user": |
| sectusers.append(value) |
| if insection: |
| merge_gitblit_section(repoacl, sectrepos, sectusers) |
| f.close() |
| return repoacl |
| |
| def send_error(text): |
| print text |
| sys.exit(1) |
| |
| def check_form(form, var): |
| ret = form.getvalue(var, None) |
| if ret is None: |
| send_error('Required field "%s" is not present.' % var) |
| if isinstance(ret, list): |
| send_error('Multiple values given for "%s". Aborting.' % var) |
| return ret |
| |
| def send_email(pkg, sha1, filename, username): |
| text = """A file has been added to the lookaside cache for %(pkg)s: |
| |
| %(sha1)s %(filename)s""" % locals() |
| msg = MIMEText(text) |
| sender_name = conf.get('mail', 'sender_name') |
| sender_email = conf.get('mail', 'sender_email') |
| sender = Utils.formataddr((sender_name, sender_email)) |
| recipient = conf.get('mail', 'recipient') |
| msg['Subject'] = 'File %s uploaded to lookaside cache by %s' % ( |
| filename, username) |
| msg['From'] = sender |
| msg['To'] = recipient |
| try: |
| s = smtplib.SMTP(conf.get('mail', 'smtp_server')) |
| s.sendmail(sender, recipient, msg.as_string()) |
| except: |
| errstr = 'sending mail for upload of %s failed!' % filename |
| print >> sys.stderr, errstr |
| syslog.syslog(errstr) |
| |
| def main(): |
| os.umask(002) |
| |
| username = os.environ.get('SSL_CLIENT_S_DN_CN', None) |
| |
| print 'Content-Type: text/plain' |
| print |
| |
| assert os.environ['REQUEST_URI'].split('/')[1] == 'lookaside' |
| |
| form = cgi.FieldStorage() |
| name = check_form(form, 'name') |
| branch = check_form(form, 'branch') |
| sha1sum = check_form(form, 'sha1sum') |
| |
| action = None |
| upload_file = None |
| filename = None |
| |
| |
| |
| if not form.has_key('file'): |
| action = 'check' |
| print >> sys.stderr, '[username=%s] Checking file status: NAME=%s BRANCH=%s SHA1SUM=%s' % (username, name, branch, sha1sum) |
| else: |
| action = 'upload' |
| upload_file = form['file'] |
| if not upload_file.file: |
| send_error('No file given for upload. Aborting.') |
| filename = os.path.basename(upload_file.filename) |
| print >> sys.stderr, '[username=%s] Processing upload request: NAME=%s BRANCH=%s SHA1SUM=%s' % (username, name, branch, sha1sum) |
| |
| module_dir = os.path.join(conf.get('lookaside', 'cache_dir'), name, branch) |
| dest_file = os.path.join(module_dir, sha1sum) |
| |
| |
| if os.path.exists(dest_file): |
| if action == 'check': |
| print 'Available' |
| else: |
| upload_file.file.close() |
| dest_file_stat = os.stat(dest_file) |
| print 'File %s already exists' % filename |
| print 'File: %s Size: %d' % (dest_file, dest_file_stat.st_size) |
| sys.exit(0) |
| elif action == 'check': |
| print 'Missing' |
| sys.exit(0) |
| |
| |
| if conf.getboolean('acl', 'do_acl'): |
| |
| repoacl = parse_gitblit_config(conf.get('acl', 'gitblit_config')) |
| |
| |
| if name not in repoacl: |
| send_error("Unknown package %s" % name) |
| |
| |
| if username not in repoacl[name]: |
| send_error("Write access package %s rejected for user %s" % (name, username)) |
| |
| |
| if not os.path.isdir(module_dir): |
| os.makedirs(module_dir, 02775) |
| |
| |
| tempfile.tempdir = module_dir |
| tmpfile = tempfile.mkstemp(sha1sum)[1] |
| tmpfd = open(tmpfile, 'w') |
| |
| |
| m = sha1_constructor() |
| filesize = 0 |
| while True: |
| data = upload_file.file.read(BUFFER_SIZE) |
| if not data: |
| break |
| tmpfd.write(data) |
| m.update(data) |
| filesize += len(data) |
| |
| |
| tmpfd.close() |
| check_sha1sum = m.hexdigest() |
| if sha1sum != check_sha1sum: |
| os.unlink(tmpfile) |
| send_error("SHA1 check failed. Received %s instead of %s." % (check_sha1sum, sha1sum)) |
| |
| |
| os.rename(tmpfile, dest_file) |
| os.chmod(dest_file, 0644) |
| |
| print >> sys.stderr, '[username=%s] Stored %s (%d bytes)' % (username, dest_file, filesize) |
| print 'File %s size %d SHA1 %s stored OK' % (filename, filesize, sha1sum) |
| if conf.getboolean('mail', 'send_mail'): |
| send_email(name, sha1sum, filename, username) |
| |
| if __name__ == '__main__': |
| main() |