def uploadyum(request): if request.method != 'PUT': return HttpServerError(request, "Invalid method") if not request.META['REMOTE_ADDR'] in settings.FTP_MASTERS: return HttpServerError(request, "Invalid client address") # We have the data in request.body. Attempt to load it as # json to ensure correct format. json.loads(request.body) # Next, check if it's the same as the current file if os.path.isfile(settings.YUM_JSON): with open(settings.YUM_JSON, "r") as f: if f.read() == request.body: # Don't rewrite the file or purge any data if nothing changed return HttpResponse("NOT CHANGED", content_type="text/plain") # File has changed - let's write it! with open("%s.new" % settings.YUM_JSON, "w") as f: f.write(request.body) os.rename("%s.new" % settings.YUM_JSON, settings.YUM_JSON) # Purge it out of varnish so we start responding right away varnish_purge("/download/js/yum.js") # Finally, indicate to the client that we're happy return HttpResponse("OK", content_type="text/plain")
def uploadftp(request): if request.method != 'PUT': return HttpServerError(request, "Invalid method") if not request.META['REMOTE_ADDR'] in settings.FTP_MASTERS: return HttpServerError(request, "Invalid client address") # We have the data in request.body. Attempt to load it as # a pickle to make sure it's properly formatted pickle.loads(request.body) # Next, check if it's the same as the current file f = open(settings.FTP_PICKLE, "rb") x = f.read() f.close() if x == request.body: # Don't rewrite the file or purge any data if nothing changed return HttpResponse("NOT CHANGED", content_type="text/plain") # File has changed - let's write it! f = open("%s.new" % settings.FTP_PICKLE, "wb") f.write(request.body) f.close() os.rename("%s.new" % settings.FTP_PICKLE, settings.FTP_PICKLE) # Purge it out of varnish so we start responding right away varnish_purge("/ftp") # Finally, indicate to the client that we're happy return HttpResponse("OK", content_type="text/plain")
def api_varnish_purge(request): if not request.META['REMOTE_ADDR'] in settings.VARNISH_PURGERS: return HttpServerError("Invalid client address") if request.method != 'POST': return HttpServerError("Can't use this way") n = int(request.POST['n']) curs = connection.cursor() for i in range(0, n): expr = request.POST['p%s' % i] curs.execute("SELECT varnish_purge_expr(%s)", (expr, )) return HttpResponse("Purged %s entries\n" % n)
def resetpwd(request): # Basic django password reset feature is completely broken. For example, it does not support # resetting passwords for users with "old hashes", which means they have no way to ever # recover. So implement our own, since it's quite the trivial feature. if request.method == "POST": try: u = User.objects.get(email__iexact=request.POST['email']) if u.password == OAUTH_PASSWORD_STORE: return HttpServerError(request, "This account cannot change password as it's connected to a third party login site.") except User.DoesNotExist: log.info("Attempting to reset password of {0}, user not found".format(request.POST['email'])) return HttpResponseRedirect('/account/reset/done/') form = PgwebPasswordResetForm(data=request.POST) if form.is_valid(): log.info("Initiating password set from {0} for {1}".format(get_client_ip(request), form.cleaned_data['email'])) token = default_token_generator.make_token(u) send_template_mail(settings.ACCOUNTS_NOREPLY_FROM, form.cleaned_data['email'], 'Password reset for your postgresql.org account', 'account/password_reset_email.txt', { 'user': u, 'uid': urlsafe_base64_encode(force_bytes(u.pk)), 'token': token, }, ) return HttpResponseRedirect('/account/reset/done/') else: form = PgwebPasswordResetForm() return render_pgweb(request, 'account', 'account/password_reset.html', { 'form': form, })
def signup(request): if request.user.is_authenticated(): return HttpServerError( request, "You must log out before you can sign up for a new account") if request.method == 'POST': # Attempt to create user then, eh? form = SignupForm(get_client_ip(request), data=request.POST) if form.is_valid(): # Attempt to create the user here # XXX: Do we need to validate something else? log.info("Creating user for {0} from {1}".format( form.cleaned_data['username'], get_client_ip(request))) user = User.objects.create_user( form.cleaned_data['username'].lower(), form.cleaned_data['email'].lower(), last_login=datetime.now()) user.first_name = form.cleaned_data['first_name'] user.last_name = form.cleaned_data['last_name'] # generate a random value for password. It won't be possible to log in with it, but # it creates more entropy for the token generator (I think). user.password = generate_random_token() user.save() # Now generate a token token = default_token_generator.make_token(user) log.info("Generated token {0} for user {1} from {2}".format( token, form.cleaned_data['username'], get_client_ip(request))) # Generate an outgoing email send_template_mail( settings.ACCOUNTS_NOREPLY_FROM, form.cleaned_data['email'], 'Your new postgresql.org community account', 'account/new_account_email.txt', { 'uid': urlsafe_base64_encode(force_bytes(user.id)), 'token': token, 'user': user }) return HttpResponseRedirect('/account/signup/complete/') else: form = SignupForm(get_client_ip(request)) return render_pgweb( request, 'account', 'base/form.html', { 'form': form, 'formitemtype': 'Account', 'form_intro': """ To sign up for a free community account, enter your preferred userid and email address. Note that a community account is only needed if you want to submit information - all content is available for reading without an account. A confirmation email will be sent to the specified address, and once confirmed a password for the new account can be specified. """, 'savebutton': 'Sign up', 'operation': 'New', 'recaptcha': True, })
def changepwd(request): if hasattr(request.user, 'password') and request.user.password == OAUTH_PASSWORD_STORE: return HttpServerError(request, "This account cannot change password as it's connected to a third party login site.") log.info("Initiating password change from {0}".format(get_client_ip(request))) return authviews.password_change(request, template_name='account/password_change.html', post_change_redirect='/account/changepwd/done/')
def vote(request, surveyid): surv = get_object_or_404(Survey, pk=surveyid) # Check that we have a valid answer number try: ansnum = int(request.POST['answer']) if ansnum < 1 or ansnum > 8: return HttpServerError(request, "Invalid answer") except: # When no answer is given, redirect to results instead return HttpResponseRedirect("/community/survey/%s-%s" % (surv.id, slugify(surv.question))) attrname = "tot%s" % ansnum # Do IP based locking... addr = get_client_ip(request) # Clean out any old junk curs = connection.cursor() curs.execute( "DELETE FROM survey_surveylock WHERE (\"time\" + '15 minutes') < now()" ) # Check if we are locked lock = SurveyLock.objects.filter(ipaddr=addr) if len(lock) > 0: return HttpServerError( request, "Too many requests from your IP in the past 15 minutes") # Generate a new lock item, and store it lock = SurveyLock(ipaddr=addr) lock.save() answers = SurveyAnswer.objects.get_or_create(survey=surv)[0] setattr(answers, attrname, getattr(answers, attrname) + 1) answers.save() # Do explicit varnish purge, since it seems that the model doesn't # do it properly. Possibly because of the cute stuff we do with # getattr/setattr above. varnish_purge("/community/survey/%s/" % surveyid) return HttpResponseRedirect("/community/survey/%s/" % surveyid)
def confirm_change_email(request, tokenhash): tokens = EmailChangeToken.objects.filter(user=request.user, token=tokenhash) token = len(tokens) and tokens[0] or None if request.user.password == OAUTH_PASSWORD_STORE: # Link shouldn't exist in this case, so just throw an unfriendly # error message. return HttpServerError(request, "This account cannot change email address as it's connected to a third party login site.") if token: # Valid token find, so change the email address request.user.email = token.email.lower() request.user.save() token.delete() return render_pgweb(request, 'account', 'account/emailchangecompleted.html', { 'token': tokenhash, 'success': token and True or False, })
def ftpbrowser(request, subpath): if subpath: # An actual path has been selected. Fancy! if subpath.find('..') > -1: # Just claim it doesn't exist if the user tries to do this # type of bad thing raise Http404 subpath = subpath.strip('/') else: subpath="" # Pickle up the list of things we need try: f = open(settings.FTP_PICKLE, "rb") allnodes = pickle.load(f) f.close() except Exception, e: return HttpServerError(request, "Failed to load ftp site information: %s" % e)
def change_email(request): tokens = EmailChangeToken.objects.filter(user=request.user) token = len(tokens) and tokens[0] or None if request.user.password == OAUTH_PASSWORD_STORE: # Link shouldn't exist in this case, so just throw an unfriendly # error message. return HttpServerError( request, "This account cannot change email address as it's connected to a third party login site." ) if request.method == 'POST': form = ChangeEmailForm(request.user, data=request.POST) if form.is_valid(): # If there is an existing token, delete it if token: token.delete() # Create a new token token = EmailChangeToken(user=request.user, email=form.cleaned_data['email'].lower(), token=generate_random_token()) token.save() send_template_mail(settings.ACCOUNTS_NOREPLY_FROM, form.cleaned_data['email'], 'Your postgresql.org community account', 'account/email_change_email.txt', { 'token': token, 'user': request.user, }) return HttpResponseRedirect('done/') else: form = ChangeEmailForm(request.user) return render_pgweb(request, 'account', 'account/emailchangeform.html', { 'form': form, 'token': token, })
def api_repo_updated(request): if not get_client_ip(request) in settings.SITE_UPDATE_HOSTS: return HttpServerError("Invalid client address") # Ignore methods and contents, just drop the trigger open(settings.SITE_UPDATE_TRIGGER_FILE, 'a').close() return HttpResponse("OK")
def signup_oauth(request): if not request.session.has_key('oauth_email') \ or not request.session.has_key('oauth_firstname') \ or not request.session.has_key('oauth_lastname'): return HttpServerError(request, 'Invalid redirect received') if request.method == 'POST': # Second stage, so create the account. But verify that the # nonce matches. data = request.POST.copy() data['email'] = request.session['oauth_email'].lower() data['first_name'] = request.session['oauth_firstname'] data['last_name'] = request.session['oauth_lastname'] form = SignupOauthForm(data=data) if form.is_valid(): log.info("Creating user for {0} from {1} from oauth signin of email {2}".format(form.cleaned_data['username'], get_client_ip(request), request.session['oauth_email'])) user = User.objects.create_user(form.cleaned_data['username'].lower(), request.session['oauth_email'].lower(), last_login=datetime.now()) user.first_name = request.session['oauth_firstname'] user.last_name = request.session['oauth_lastname'] user.password = OAUTH_PASSWORD_STORE user.save() # Clean up our session del request.session['oauth_email'] del request.session['oauth_firstname'] del request.session['oauth_lastname'] request.session.modified = True # We can immediately log the user in because their email # is confirmed. user.backend = settings.AUTHENTICATION_BACKENDS[0] django_login(request, user) # Redirect to the sessions page, or to the account page # if none was given. return HttpResponseRedirect(request.session.pop('login_next', '/account/')) elif request.GET.has_key('do_abort'): del request.session['oauth_email'] del request.session['oauth_firstname'] del request.session['oauth_lastname'] request.session.modified = True return HttpResponseRedirect(request.session.pop('login_next', '/')) else: # Generate possible new username suggested_username = request.session['oauth_email'].replace('@', '.')[:30] # Auto generation requires firstnamea and lastname to be specified f = request.session['oauth_firstname'].lower() l = request.session['oauth_lastname'].lower() if f and l: for u in itertools.chain([ u"{0}{1}".format(f, l[0]), u"{0}{1}".format(f[0], l), ], (u"{0}{1}{2}".format(f, l[0], n) for n in xrange(100))): if not User.objects.filter(username=u[:30]).exists(): suggested_username = u[:30] break form = SignupOauthForm(initial={ 'username': suggested_username, 'email': request.session['oauth_email'].lower(), 'first_name': request.session['oauth_firstname'][:30], 'last_name': request.session['oauth_lastname'][:30], }) return render_pgweb(request, 'account', 'account/signup_oauth.html', { 'form': form, 'operation': 'New account', 'savebutton': 'Sign up for new account', 'recaptcha': True, })
def ftpbrowser(request, subpath): if subpath: # An actual path has been selected. Fancy! if subpath.find('..') > -1: # Just claim it doesn't exist if the user tries to do this # type of bad thing raise Http404 subpath = subpath.strip('/') else: subpath = "" # Pickle up the list of things we need try: f = open(settings.FTP_PICKLE, "rb") allnodes = pickle.load(f) f.close() except Exception as e: return HttpServerError(request, "Failed to load ftp site information: %s" % e) # An incoming subpath may either be canonical, or have one or more elements # present that are actually symlinks. For each element of the path, test to # see if it is present in the pickle. If not, look for a symlink entry with # and if present, replace the original entry with the symlink target. canonpath = '' if subpath != '': parent = '' for d in subpath.split('/'): # Check if allnodes contains a node matching the path if d in allnodes[parent]: if allnodes[parent][d]['t'] == 'd': canonpath = os.path.join(canonpath, d) elif allnodes[parent][d]['t'] == 'l': canonpath = os.path.join( canonpath, allnodes[parent][d]['d']).strip('/') else: # There's a matching node, but it's not a link or a directory raise Http404 parent = canonpath else: # There's no matching node raise Http404 # If we wound up with a canonical path that doesn't match the original request, # redirect the user canonpath = canonpath.strip('/') if subpath != canonpath: return HttpResponseRedirect('/ftp/' + canonpath) node = allnodes[subpath] del allnodes # Add all directories directories = [{ 'link': k, 'url': k, 'type': 'd' } for k, v in list(node.items()) if v['t'] == 'd'] # Add all symlinks (only directories supported) directories.extend([{ 'link': k, 'url': v['d'], 'type': 'l' } for k, v in list(node.items()) if v['t'] == 'l']) # A little early sorting wouldn't go amiss, so .. ends up at the top directories.sort(key=version_sort, reverse=True) # Add a link to the parent directory if subpath: directories.insert(0, {'link': '[Parent Directory]', 'url': '..'}) # Fetch files files = [{ 'name': k, 'mtime': v['d'], 'size': v['s'] } for k, v in list(node.items()) if v['t'] == 'f'] breadcrumbs = [] if subpath: breadroot = "" for pathpiece in subpath.split('/'): if not pathpiece: # Trailing slash will give out an empty pathpiece continue if breadroot: breadroot = "%s/%s" % (breadroot, pathpiece) else: breadroot = pathpiece breadcrumbs.append({'name': pathpiece, 'path': breadroot}) # Check if there are any "content files" we should render directly on the webpage file_readme = ('README' in node and node['README']['t'] == 'f') and node['README']['c'] or None file_message = ('.message' in node and node['.message']['t'] == 'f') and node['.message']['c'] or None file_maintainer = ('CURRENT_MAINTAINER' in node and node['CURRENT_MAINTAINER']['t'] == 'f') and node['CURRENT_MAINTAINER']['c'] or None del node return render_pgweb( request, 'download', 'downloads/ftpbrowser.html', { 'basepath': subpath.rstrip('/'), 'directories': directories, 'files': sorted(files, key=lambda f: f['name']), 'breadcrumbs': breadcrumbs, 'readme': file_readme, 'messagefile': file_message, 'maintainer': file_maintainer, })