Skip to content

Commit

Permalink
working on invites, doing some refactoring and testing as well
Browse files Browse the repository at this point in the history
  • Loading branch information
hydrogen18 committed Aug 11, 2013
1 parent 20bb5bc commit fe54bd8
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 56 deletions.
39 changes: 1 addition & 38 deletions auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@


class Auth(object):
def __init__(self,salt):
self.salt = salt
def __init__(self):
self.log = logging.getLogger('fairywren.auth')
self.log.info('Created')

Expand Down Expand Up @@ -48,43 +47,7 @@ def changePassword(self,userId,pwHash):

return True

def _saltPwhash(self,pwHash):
storedHash = hashlib.sha512()
storedHash.update(self.salt)
storedHash.update(pwHash)
return base64.urlsafe_b64encode(storedHash.digest()).replace('=','')

def addUser(self,username,pwHash):
self.log.debug('Trying to add user %s',username)
secretKey = hashlib.sha512()

randomValue = os.urandom(1024)
secretKey.update(randomValue)

saltedPw = self._saltPwhash(pwHash)

with self.connPool.item() as conn:
cur = conn.cursor()

try:
cur.execute("INSERT into users (name,password,secretKey) VALUES(%s,%s,%s) returning users.id;",
(username,
saltedPw,
base64.urlsafe_b64encode(secretKey.digest()).replace('=',''),) )
except IntegrityError as e:
self.log.error(e)
conn.rollback()
cur.close()
return None

conn.commit()

newId, = cur.fetchone()
cur.close()
conn.close()
self.log.debug('Added user, new id %.8x', newId)
return 'api/users/%.8x' % newId


def authenticateSecretKey(self,key):
with self.connPool.item() as conn:
Expand Down
10 changes: 10 additions & 0 deletions fairywren.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ CREATE TABLE torrents(
PRIMARY KEY(id,infoHash)
);

CREATE TABLE invites(
id SERIAL UNIQUE,
secret char(43) UNIQUE,
inviter INTEGER REFERENCES users(id) NOT NULL,
creationDate TIMESTAMP WITHOUT TIME ZONE NOT NULL,
invitee INTEGER REFERENCES users(id) NULL,
accepted TIMESTAMP WITHOUT TIME ZONE NULL,
PRIMARY KEY(id)
);

CREATE TABLE roles(
id SERIAL UNIQUE,
name varchar NOT NULL UNIQUE,
Expand Down
2 changes: 1 addition & 1 deletion html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<form>
<label for="username">Username:</label> <input id="username" type="text" size="24"/><br />
<label for="password">Password:</label> <input id="password" type="password" size="24"/> <br />
<input type="submit" value="submit" onclick="Fairywren.login(); return false;"/>
<input type="submit" value="Login" onclick="Fairywren.login(); return false;"/>
</form>
</div>

Expand Down
40 changes: 40 additions & 0 deletions html/invite.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

<html>

<head>
<title>
Invite
</title>
</head>

<body>

<script src="js/sha.js"></script>
<script src="js/jquery.js"></script>

<script src="js/fairywren.js"></script>
<script src="js/invite.js"></script>

<link rel="stylesheet" type="text/css" href="torrents.css">

<div id="main" align="center">

<div id="message" style="color:red;">

</div>

<div class="contentBox" style="text-align:center; align:center;width:26em;min-width:23em;">
<div class="contentBoxHeader" style="align:center;">Register</div>
<form>
<label for="username">Username:</label> <input id="username" type="text" size="24"/><br />
<label for="password">Password:</label> <input id="password0" type="password" size="24"/> <br />
<label for="password">Confirm Password:</label> <input id="password1" type="password" size="24"/> <br />
<input id="register" type="submit" value="Register" onclick="Fairywren.register(); return false;"/>
</form>
</div>

</div>

</body>

</html>
13 changes: 11 additions & 2 deletions html/js/fairywren.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Fairywren = {};

Fairywren.MIN_PASSWORD_LENGTH = 12;
Fairywren.MIN_USERNAME_LENGTH = 4;

Fairywren.serverErrorHandler = function(jqXhr,textStatus,errorThrown,element)
{
Expand Down Expand Up @@ -77,13 +78,21 @@ Fairywren.validateUsername = function(username)
for(var i = 0 ; i < username.length;++i){
if ( -1 === ACCEPTED.indexOf(username[i]))
{
rejected.push(username[i]);
if(rejected.indexOf(username[i])===-1)
{
rejected.push(username[i]);
}
}
}

if(rejected.length !==0)
{
return 'The following characters are not allowed in usernames: ' + rejected.join('');
return 'The following characters are not allowed in usernames: "' + rejected.join('') + '"';
}

if(username.length < Fairywren.MIN_USERNAME_LENGTH)
{
return 'Username too short';
}

return null;
Expand Down
64 changes: 64 additions & 0 deletions html/js/invite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
$(document).ready(function(){
var hash = window.location.hash;

var registerButton = $("input#register");

if(hash.length === 0)
{
//User got here on accident or something. Display error message
//and depart
}

var inviteHref = hash.slice(1);

//Retrieve the invite, check to see if it is valid
jQuery.get(inviteHref).
done(
function(data)
{
//Check to see if it has been claimed


}
).fail(function(jqXhr,textStatus,errorThrown)
{
Fairywren.serverErrorHandler(jqXhr,textStatus,errorThrown,$("#message"));

});

});

Fairywren.register = function()
{
var errDisplay = $("#message");
errDisplay.text('');
var username = $("input#username");

var validUsername = Fairywren.validateUsername(username.val());

if(validUsername !== null)
{
errDisplay.text(validUsername);
return;
}

var password0 = $("input#password0");
var password1 = $("input#password1");


var validPassword = Fairywren.validatePassword(password0.val());
if( validPassword !== null)
{
errDisplay.text(validPassword);
return;
}

if(password0.val() !== password1.val())
{
errDisplay.text("Password does not match");
return;
}

}


2 changes: 2 additions & 0 deletions permissions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ GRANT UPdATE,SELECT on users_id_seq to webapi;
GRANT ALL on roles to webapi;
GRANT UPDATE,SELECT on roles_id_seq to webapi;
GRANT ALL on rolemember to webapi;
GRANT ALL on invites to webapi;
GRANT UPDATE,SELECT on invites_id_seq to webapi;

GRANT SELECT on torrents to tracker;
GRANT SELECT on users to tracker;
15 changes: 15 additions & 0 deletions test/testUsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,22 @@
import getpass
import signal

from TestPostgres import TestPostgres
import users

class TestUsersEmptyDatabase(TestPostgres):
def setUp(self):
TestPostgres.setUp(self)
self.users = users.Users()
self.users.setConnectionPool(self.getConnectionPool())

def test_createInvite(self):
with self.assertRaisesRegexp(ValueError,'.*uid.*') as cm:
self.users.createInvite(0)


def test_getInfo(self):
self.assertEqual(None,self.users.getInfo(0))


if __name__ == '__main__':
Expand Down
19 changes: 11 additions & 8 deletions test/testWebApi.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@ def getCount(self,info_hash):
class MockUsers(object):
def __init__(self):
self._getInfo = {'numberOfTorrents' : 0, 'name':'aTestUser', 'password' : fairywren.USER_PASSWORD_FMT % 1}
self._addUser = None
def getInfo(self,idNumber):
return self._getInfo

def addUser(self,username,password):
return self._addUser

class MockAuth(object):
def __init__(self):
self._authenticateUser = 1
self._addUser = None

self._isUserMemberOfRole = False

def isUserMemberOfRole(self,userId,roles):
Expand All @@ -37,8 +41,7 @@ def isUserMemberOfRole(self,userId,roles):
def authenticateUser(self,username,password):
return self._authenticateUser

def addUser(self,username,password):
return self._addUser


class MockTorrents(object):
def __init__(self):
Expand Down Expand Up @@ -458,7 +461,7 @@ def test_getself(self):

class TestAddUser(AuthenticatedWebApiTest):
def test_userAlreadyExists(self):
self.auth._addUser = None
self.users._addUser = None
self.auth._isUserMemberOfRole = True
try:
self.urlopen('http://webapi/users', data= urllib.urlencode({'username':'foo','password':86*'0'}))
Expand All @@ -470,17 +473,17 @@ def test_userAlreadyExists(self):
self.assertTrue(False)

def test_ok(self):
self.auth._addUser = 'FOO'
self.users._addUser = 'FOO'
self.auth._isUserMemberOfRole = True

r = self.urlopen('http://webapi/users', data= urllib.urlencode({'username':'foo','password':86*'0'}))
self.assertEqual(200,r.code)
r = json.loads(r.read())
self.assertIn('href',r)
self.assertEqual(r['href'],self.auth._addUser)
self.assertEqual(r['href'],self.users._addUser)

def test_badPassword(self):
self.auth._addUser = 'meow'
self.users._addUser = 'meow'
self.auth._isUserMemberOfRole = True
try:
self.urlopen('http://webapi/users', data= urllib.urlencode({'username':'foo','password':85*'0'}))
Expand All @@ -493,7 +496,7 @@ def test_badPassword(self):
self.assertTrue(False)

def test_missingPassword(self):
self.auth._addUser = 'meow'
self.users._addUser = 'meow'
self.auth._isUserMemberOfRole = True
try:
self.urlopen('http://webapi/users', data= urllib.urlencode({'username':'foo'}))
Expand Down
Loading

0 comments on commit fe54bd8

Please sign in to comment.