mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-26 15:28:37 -05:00
Split the admin cookie out from the session cookie.
This commit is contained in:
@@ -91,6 +91,8 @@ shutdown_secret = 12345
|
||||
https_endpoint =
|
||||
# name of the cookie to drop with login information
|
||||
login_cookie = reddit_session
|
||||
# name of the admin cookie
|
||||
admin_cookie = reddit_admin
|
||||
# the work factor for bcrypt, increment this every time computers double in
|
||||
# speed. don't worry, changing this won't break old passwords
|
||||
bcrypt_work_factor = 12
|
||||
@@ -385,6 +387,8 @@ REPLY_AGE_LIMIT = 180
|
||||
VOTE_AGE_LIMIT = 180
|
||||
# minimum age, in days, of an account to be eligible to create a community
|
||||
min_membership_create_community = 30
|
||||
# how long the admin cookie should be valid for (in seconds)
|
||||
ADMIN_COOKIE_TTL = 1800
|
||||
|
||||
# min amount of karma to edit
|
||||
WIKI_KARMA = 100
|
||||
|
||||
@@ -2462,5 +2462,5 @@ class ApiController(RedditController):
|
||||
if form.has_errors('password', errors.WRONG_PASSWORD):
|
||||
return
|
||||
|
||||
self.login(c.user, admin = True, rem = True)
|
||||
self.enable_admin_mode(c.user)
|
||||
form.redirect(dest)
|
||||
|
||||
@@ -36,10 +36,9 @@ class ButtonjsController(MinimalController):
|
||||
MinimalController.pre(self)
|
||||
# override user loggedin behavior to ensure this page always
|
||||
# uses the page cache
|
||||
(user, maybe_admin) = \
|
||||
valid_cookie(c.cookies[g.login_cookie].value
|
||||
if g.login_cookie in c.cookies
|
||||
else '')
|
||||
user = valid_cookie(c.cookies[g.login_cookie].value
|
||||
if g.login_cookie in c.cookies
|
||||
else '')
|
||||
if user:
|
||||
self.user_is_loggedin = True
|
||||
|
||||
|
||||
@@ -1076,7 +1076,7 @@ class FormsController(RedditController):
|
||||
"""disable admin interaction with site."""
|
||||
if not c.user.name in g.admins:
|
||||
return self.abort404()
|
||||
self.login(c.user, admin = False, rem = True)
|
||||
self.disable_admin_mode(c.user)
|
||||
return self.redirect(dest)
|
||||
|
||||
def GET_validuser(self):
|
||||
|
||||
@@ -29,7 +29,7 @@ from r2.lib import pages, utils, filters, amqp, stats
|
||||
from r2.lib.utils import http_utils, is_subdomain, UniqueIterator, ip_and_slash16
|
||||
from r2.lib.cache import LocalCache, make_key, MemcachedError
|
||||
import random as rand
|
||||
from r2.models.account import valid_cookie, FakeAccount, valid_feed
|
||||
from r2.models.account import valid_cookie, FakeAccount, valid_feed, valid_admin_cookie
|
||||
from r2.models.subreddit import Subreddit
|
||||
from r2.models import *
|
||||
from errors import ErrorSet
|
||||
@@ -40,7 +40,7 @@ from r2.lib.jsontemplates import api_type, is_api
|
||||
from Cookie import CookieError
|
||||
from copy import copy
|
||||
from Cookie import CookieError
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import sha1, md5
|
||||
from urllib import quote, unquote
|
||||
import simplejson
|
||||
@@ -746,14 +746,25 @@ class MinimalController(BaseController):
|
||||
class RedditController(MinimalController):
|
||||
|
||||
@staticmethod
|
||||
def login(user, admin = False, rem = False):
|
||||
c.cookies[g.login_cookie] = Cookie(value = user.make_cookie(admin = admin),
|
||||
def login(user, rem=False):
|
||||
c.cookies[g.login_cookie] = Cookie(value = user.make_cookie(),
|
||||
expires = NEVER if rem else None)
|
||||
|
||||
@staticmethod
|
||||
def logout(admin = False):
|
||||
def logout():
|
||||
c.cookies[g.login_cookie] = Cookie(value='', expires=DELETE)
|
||||
|
||||
@staticmethod
|
||||
def enable_admin_mode(user):
|
||||
expiration_time = datetime.utcnow() + timedelta(seconds=g.ADMIN_COOKIE_TTL)
|
||||
expiration = expiration_time.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
c.cookies[g.admin_cookie] = Cookie(value=user.make_admin_cookie(),
|
||||
expires=expiration)
|
||||
|
||||
@staticmethod
|
||||
def disable_admin_mode(user):
|
||||
c.cookies[g.admin_cookie] = Cookie(value='', expires=DELETE)
|
||||
|
||||
def pre(self):
|
||||
c.response_wrappers = []
|
||||
MinimalController.pre(self)
|
||||
@@ -781,12 +792,15 @@ class RedditController(MinimalController):
|
||||
# no logins for RSS feed unless valid_feed has already been called
|
||||
if not c.user:
|
||||
if c.extension != "rss":
|
||||
(c.user, maybe_admin) = \
|
||||
valid_cookie(c.cookies[g.login_cookie].value
|
||||
if g.login_cookie in c.cookies
|
||||
else '')
|
||||
if c.user:
|
||||
c.user_is_loggedin = True
|
||||
session_cookie = c.cookies.get(g.login_cookie)
|
||||
if session_cookie:
|
||||
c.user = valid_cookie(session_cookie.value)
|
||||
if c.user:
|
||||
c.user_is_loggedin = True
|
||||
|
||||
admin_cookie = c.cookies.get(g.admin_cookie)
|
||||
if c.user_is_loggedin and admin_cookie:
|
||||
maybe_admin = valid_admin_cookie(admin_cookie.value)
|
||||
|
||||
if not c.user:
|
||||
c.user = UnloggedUser(get_browser_langs())
|
||||
|
||||
@@ -116,6 +116,7 @@ class Globals(object):
|
||||
'MODWINDOW',
|
||||
'RATELIMIT',
|
||||
'QUOTA_THRESHOLD',
|
||||
'ADMIN_COOKIE_TTL',
|
||||
'num_comments',
|
||||
'max_comments',
|
||||
'max_comments_gold',
|
||||
|
||||
@@ -753,11 +753,10 @@ class AdminModeInterstitial(BoringPage):
|
||||
*args, **kwargs)
|
||||
|
||||
def content(self):
|
||||
return PasswordVerificationForm("adminon", dest=self.dest)
|
||||
return PasswordVerificationForm(dest=self.dest)
|
||||
|
||||
class PasswordVerificationForm(Templated):
|
||||
def __init__(self, api, dest):
|
||||
self.api = api
|
||||
def __init__(self, dest):
|
||||
self.dest = dest
|
||||
Templated.__init__(self)
|
||||
|
||||
|
||||
@@ -30,12 +30,15 @@ from r2.lib.cache import sgm
|
||||
from r2.lib import filters
|
||||
from r2.lib.log import log_text
|
||||
|
||||
from pylons import g
|
||||
from pylons import c, g, request
|
||||
from pylons.i18n import _
|
||||
import time, sha
|
||||
from copy import copy
|
||||
from datetime import datetime, timedelta
|
||||
import bcrypt
|
||||
import hmac
|
||||
import hashlib
|
||||
|
||||
|
||||
class AccountExists(Exception): pass
|
||||
|
||||
@@ -202,16 +205,22 @@ class Account(Thing):
|
||||
(self.name, prev_visit, current_time))
|
||||
set_last_visit(self)
|
||||
|
||||
def make_cookie(self, timestr = None, admin = False):
|
||||
def make_cookie(self, timestr=None):
|
||||
if not self._loaded:
|
||||
self._load()
|
||||
timestr = timestr or time.strftime('%Y-%m-%dT%H:%M:%S')
|
||||
id_time = str(self._id) + ',' + timestr
|
||||
to_hash = ','.join((id_time, self.password, g.SECRET))
|
||||
if admin:
|
||||
to_hash += 'admin'
|
||||
return id_time + ',' + sha.new(to_hash).hexdigest()
|
||||
|
||||
def make_admin_cookie(self, timestr=None):
|
||||
if not self._loaded:
|
||||
self._load()
|
||||
timestr = timestr or datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S')
|
||||
hashable = ','.join((timestr, request.ip, request.user_agent, self.password))
|
||||
mac = hmac.new(g.SECRET, hashable, hashlib.sha1).hexdigest()
|
||||
return ','.join((timestr, mac))
|
||||
|
||||
def needs_captcha(self):
|
||||
return not g.disable_captcha and self.link_karma < 1
|
||||
|
||||
@@ -554,23 +563,46 @@ def valid_cookie(cookie):
|
||||
uid, timestr, hash = cookie.split(',')
|
||||
uid = int(uid)
|
||||
except:
|
||||
return (False, False)
|
||||
return False
|
||||
|
||||
if g.read_only_mode:
|
||||
return (False, False)
|
||||
return False
|
||||
|
||||
try:
|
||||
account = Account._byID(uid, True)
|
||||
if account._deleted:
|
||||
return (False, False)
|
||||
return False
|
||||
except NotFound:
|
||||
return (False, False)
|
||||
return False
|
||||
|
||||
if constant_time_compare(cookie, account.make_cookie(timestr)):
|
||||
return account
|
||||
return False
|
||||
|
||||
|
||||
def valid_admin_cookie(cookie):
|
||||
if g.read_only_mode:
|
||||
return False
|
||||
|
||||
# parse the cookie
|
||||
try:
|
||||
timestr, hash = cookie.split(',')
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
# make sure it's a recent cookie
|
||||
try:
|
||||
cookie_time = datetime.strptime(timestr, '%Y-%m-%dT%H:%M:%S')
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
cookie_age = datetime.utcnow() - cookie_time
|
||||
if cookie_age.total_seconds() > g.ADMIN_COOKIE_TTL:
|
||||
return False
|
||||
|
||||
# validate
|
||||
return constant_time_compare(cookie, c.user.make_admin_cookie(timestr))
|
||||
|
||||
if constant_time_compare(cookie, account.make_cookie(timestr, admin = False)):
|
||||
return (account, False)
|
||||
elif constant_time_compare(cookie, account.make_cookie(timestr, admin = True)):
|
||||
return (account, True)
|
||||
return (False, False)
|
||||
|
||||
def valid_feed(name, feedhash, path):
|
||||
if name and feedhash and path:
|
||||
|
||||
Reference in New Issue
Block a user