def test_show(self): with helper.clear_tables(self.conn, self.cursor, ['responses']): responses = Table('responses') self.cursor.execute( Query.into(responses).columns( responses.name, responses.response_body, responses.description).insert( *[Parameter('%s') for _ in range(3)]).get_sql(), ('foobar', 'body', 'desc')) self.conn.commit() with helper.user_with_token(self.conn, self.cursor, ['responses']) as (user_id, token): r = requests.get(HOST + '/responses/foobar', headers={'Authorization': f'bearer {token}'}) r.raise_for_status() self.assertEqual(r.status_code, 200) body = r.json() self.assertIsInstance(body, dict) self.assertIsInstance(body.get('id'), int) self.assertIsInstance(body.get('name'), str) self.assertIsInstance(body.get('body'), str) self.assertIsInstance(body.get('desc'), str) self.assertIsInstance(body.get('created_at'), int) self.assertIsInstance(body.get('updated_at'), int) self.assertEqual(body['name'], 'foobar') self.assertEqual(body['body'], 'body') self.assertEqual(body['desc'], 'desc')
def test_edit(self): with helper.clear_tables(self.conn, self.cursor, ['responses', 'response_histories']),\ helper.user_with_token(self.conn, self.cursor, ['responses']) as (user_id, token): r = requests.post(f'{HOST}/responses', headers={'authorization': f'bearer {token}'}, json={ 'name': 'foobar', 'body': 'my body', 'desc': 'my desc' }) r.raise_for_status() self.assertEqual(r.status_code, 200) r = requests.post(f'{HOST}/responses/foobar', headers={'authorization': f'bearer {token}'}, json={ 'body': 'new body', 'desc': 'new desc', 'edit_reason': 'new edit reason' }) r.raise_for_status() self.assertEqual(r.status_code, 200) r = requests.get(f'{HOST}/responses/foobar', headers={'authorization': f'bearer {token}'}) r.raise_for_status() self.assertEqual(r.status_code, 200) body = r.json() self.assertEqual(body['body'], 'new body') self.assertEqual(body['desc'], 'new desc')
def test_index(self): with helper.clear_tables(self.conn, self.cursor, ['responses']): responses = Table('responses') self.cursor.execute( Query.into(responses).columns( responses.name, responses.response_body, responses.description).insert( *[Parameter('%s') for _ in range(3)]).get_sql(), ('foobar', 'body', 'desc')) with helper.user_with_token(self.conn, self.cursor, ['responses']) as (user_id, token): r = requests.get(HOST + '/responses', headers={'Authorization': f'bearer {token}'}) r.raise_for_status() self.assertEqual(r.status_code, 200) body = r.json() self.assertIsInstance(body, dict) self.assertIsInstance(body.get('responses'), list) self.assertEqual(len(body), 1) res_arr = body['responses'] self.assertEqual(len(res_arr), 1) self.assertIsInstance(res_arr[0], str) self.assertEqual(res_arr[0], 'foobar')
def test_failed_passwd_auth(self): with helper.clear_tables(self.conn, self.cursor, ['users']): users = Table('users') self.cursor.execute( Query.into(users).columns(users.username).insert( Parameter('%s')).returning(users.id).get_sql(), ('testuser', )) (user_id, ) = self.cursor.fetchone() passwd_hsh = b64encode( pbkdf2_hmac('sha256', 'testpass'.encode('utf-8'), 'salt'.encode('utf-8'), 10)).decode('ascii') pauths = Table('password_authentications') self.cursor.execute( Query.into(pauths).columns( pauths.user_id, pauths.human, pauths.hash_name, pauths.hash, pauths.salt, pauths.iterations).insert(Parameter('%s'), True, Parameter('%s'), Parameter('%s'), Parameter('%s'), Parameter('%s')).get_sql(), (user_id, 'sha256', passwd_hsh, 'salt', 10)) self.conn.commit() r = requests.post(f'{HOST}/users/login', json={ 'user_id': user_id, 'username': '******', 'password': '******', 'captcha_token': 'notoken' }) self.assertNotEqual(r.status_code, 200) self.assertLess(r.status_code, 500)
def test_create(self): with helper.clear_tables(self.conn, self.cursor, ['responses', 'response_histories']),\ helper.user_with_token(self.conn, self.cursor, ['responses']) as (user_id, token): r = requests.post(f'{HOST}/responses', headers={'authorization': f'bearer {token}'}, json={ 'name': 'foobar', 'body': 'my body', 'desc': 'my desc' }) r.raise_for_status() self.assertEqual(r.status_code, 200) responses = Table('responses') self.cursor.execute( Query.from_(responses).select( responses.id, responses.response_body, responses.description).where( responses.name == Parameter('%s')).get_sql(), ('foobar', )) row = self.cursor.fetchone() self.assertIsNotNone(row) (respid, body, desc) = row self.assertEqual(body, 'my body') self.assertEqual(desc, 'my desc') resp_hists = Table('response_histories') self.cursor.execute( Query.from_(resp_hists).select(1).where( resp_hists.response_id == Parameter('%s')).limit( 1).get_sql(), (respid, )) row = self.cursor.fetchone() self.assertIsNotNone(row)
def test_failed_claim_token(self): with helper.clear_tables(self.conn, self.cursor, ['users']): users = Table('users') self.cursor.execute( Query.into(users).columns(users.username).insert( Parameter('%s')).returning(users.id).get_sql(), ('testuser', )) (user_id, ) = self.cursor.fetchone() claim_tokens = Table('claim_tokens') self.cursor.execute( Query.into(claim_tokens).columns( claim_tokens.user_id, claim_tokens.token, claim_tokens.expires_at).insert(Parameter('%s'), Parameter('%s'), Now()).get_sql(), (user_id, 'testtoken')) self.conn.commit() r = requests.post(f'{HOST}/users/claim', json={ 'user_id': user_id, 'claim_token': 'testtoken2', 'password': '******', 'captcha': 'notoken' }) self.assertNotEqual(200, r.status_code) self.assertLess(r.status_code, 500) pauths = Table('password_authentications') self.cursor.execute( Query.from_(pauths).select(pauths.user_id, pauths.human, pauths.hash_name, pauths.hash, pauths.salt, pauths.iterations).get_sql()) row = self.cursor.fetchone() self.assertIsNone(row)
def test_create_unstripped(self): with helper.clear_tables(self.conn, self.cursor, ['responses', 'response_histories']),\ helper.user_with_token(self.conn, self.cursor, ['responses']) as (user_id, token): r = requests.post(f'{HOST}/responses', headers={'authorization': f'bearer {token}'}, json={ 'name': ' foobar', 'body': 'my body', 'desc': 'my desc' }) self.assertEqual(r.status_code, 422)
def test_login_passwd_long(self): # It should not attempt to service this request as it would be # computationally very expensive to hash a password this long # (256 chars) with helper.clear_tables(self.conn, self.cursor, ['users']): r = requests.post(f'{HOST}/users/login', json={ 'user_id': 1, 'username': '******', 'password': '******' * (256 // 4), 'captcha_token': 'notoken' }) self.assertEqual(r.status_code, 400)
def test_passwd_auth_to_authtoken(self): with helper.clear_tables(self.conn, self.cursor, ['users']): users = Table('users') self.cursor.execute( Query.into(users).columns(users.username).insert( Parameter('%s')).returning(users.id).get_sql(), ('testuser', )) (user_id, ) = self.cursor.fetchone() passwd_hsh = b64encode( pbkdf2_hmac('sha256', 'testpass'.encode('utf-8'), 'salt'.encode('utf-8'), 10)).decode('ascii') pauths = Table('password_authentications') self.cursor.execute( Query.into(pauths).columns( pauths.user_id, pauths.human, pauths.hash_name, pauths.hash, pauths.salt, pauths.iterations).insert(Parameter('%s'), True, Parameter('%s'), Parameter('%s'), Parameter('%s'), Parameter('%s')).get_sql(), (user_id, 'sha256', passwd_hsh, 'salt', 10)) self.conn.commit() r = requests.post(f'{HOST}/users/login', json={ 'user_id': user_id, 'username': '******', 'password': '******', 'captcha_token': 'notoken' }) r.raise_for_status() self.assertEqual(r.status_code, 200) body = r.json() self.assertIsInstance(body, dict) self.assertIsInstance(body.get('user_id'), int) self.assertIsInstance(body.get('token'), str) self.assertIsInstance(body.get('expires_at_utc'), float) self.assertEqual(body['user_id'], user_id) self.assertGreaterEqual(body['expires_at_utc'], time.time()) self.assertEqual(3, len(body)) token = body['token'] authtokens = Table('authtokens') self.cursor.execute( Query.from_(authtokens).select(authtokens.user_id).where( authtokens.token == Parameter('%s')).get_sql(), (token, )) row = self.cursor.fetchone() self.assertIsNotNone(row) self.assertEqual(user_id, row[0])
def test_index_no_perm(self): with helper.clear_tables(self.conn, self.cursor, ['responses']): responses = Table('responses') self.cursor.execute( Query.into(responses).columns( responses.name, responses.response_body, responses.description).insert( *[Parameter('%s') for _ in range(3)]).get_sql(), ('foobar', 'body', 'desc')) with helper.user_with_token(self.conn, self.cursor, []) as (user_id, token): r = requests.get(HOST + '/responses', headers={'Authorization': f'bearer {token}'}) self.assertEqual(r.status_code, 403)
def test_authtoken_to_users_me(self): with helper.clear_tables(self.conn, self.cursor, ['users']): users = Table('users') self.cursor.execute( Query.into(users).columns(users.username).insert( Parameter('%s')).returning(users.id).get_sql(), ('testuser', )) (user_id, ) = self.cursor.fetchone() authtokens = Table('authtokens') self.cursor.execute( Query.into(authtokens).columns( authtokens.user_id, authtokens.token, authtokens.expires_at, authtokens.source_type, authtokens.source_id).insert(Parameter('%s'), Parameter('%s'), Now() + Interval(hours=1), Parameter('%s'), Parameter('%s')).get_sql(), (user_id, 'testtoken', 'other', 1)) self.conn.commit() r = requests.get(f'{HOST}/users/{user_id}/me', headers={'Authorization': 'bearer testtoken'}) r.raise_for_status() self.assertEqual(r.status_code, 200) body = r.json() self.assertIsInstance(body, dict) self.assertIsInstance(body.get('username'), str) self.assertEqual(len(body), 1) self.assertEqual(body['username'], 'testuser') # headers self.assertIsInstance(r.headers.get('cache-control'), str) cc = r.headers.get('cache-control') self.assertIn('private', cc) self.assertIn('max-age', cc) self.assertIn('stale-while-revalidate', cc) self.assertIn('stale-if-error', cc) split_cache_control = cc.split(', ') split_cache_control.remove('private') cc_args = dict([itm.split('=') for itm in split_cache_control]) for key in list(cc_args.keys()): cc_args[key] = int(cc_args[key]) self.assertGreater(cc_args['max-age'], 0) self.assertGreater(cc_args['stale-while-revalidate'], 0) self.assertGreater(cc_args['stale-if-error'], 0)
def test_claim_token_to_passwd_auth(self): # users will cascade to everything with helper.clear_tables(self.conn, self.cursor, ['users']): users = Table('users') self.cursor.execute( Query.into(users).columns(users.username).insert( Parameter('%s')).returning(users.id).get_sql(), ('testuser', )) (user_id, ) = self.cursor.fetchone() claim_tokens = Table('claim_tokens') self.cursor.execute( Query.into(claim_tokens).columns( claim_tokens.user_id, claim_tokens.token, claim_tokens.expires_at).insert(Parameter('%s'), Parameter('%s'), Now()).get_sql(), (user_id, 'testtoken')) self.conn.commit() r = requests.post(f'{HOST}/users/claim', json={ 'user_id': user_id, 'claim_token': 'testtoken', 'password': '******', 'captcha': 'notoken' }) r.raise_for_status() self.assertEqual(r.status_code, 200) pauths = Table('password_authentications') self.cursor.execute( Query.from_(pauths).select(pauths.user_id, pauths.human, pauths.hash_name, pauths.hash, pauths.salt, pauths.iterations).get_sql()) row = self.cursor.fetchone() self.assertIsNotNone(row) self.assertIsNone(self.cursor.fetchone()) self.assertEqual(row[0], user_id) self.assertTrue(row[1]) exp_hash = b64encode( pbkdf2_hmac(row[2], 'testpass'.encode('utf-8'), row[4].encode('utf-8'), row[5])).decode('ascii') self.assertEqual(row[3], exp_hash)
def test_histories(self): with helper.clear_tables(self.conn, self.cursor, ['responses', 'response_histories']): responses = Table('responses') self.cursor.execute( Query.into(responses).columns( responses.name, responses.response_body, responses.description).insert( *[Parameter('%s') for _ in range(3)]).returning( responses.id).get_sql(), ('foobar', 'body', 'desc')) (respid, ) = self.cursor.fetchone() self.conn.commit() with helper.user_with_token(self.conn, self.cursor, ['responses']) as (user_id, token): resp_hists = Table('response_histories') self.cursor.execute( Query.into(resp_hists).columns( resp_hists.response_id, resp_hists.user_id, resp_hists.old_raw, resp_hists.new_raw, resp_hists.reason, resp_hists.old_desc, resp_hists.new_desc).insert( *[Parameter('%s') for _ in range(7)]).returning( resp_hists.id).get_sql(), (respid, user_id, 'older raw', 'body', 'testing', 'old desc', 'desc')) (hist_id, ) = self.cursor.fetchone() self.conn.commit() r = requests.get(HOST + '/responses/foobar/histories', headers={'Authorization': f'bearer {token}'}) r.raise_for_status() self.assertEqual(r.status_code, 200) body = r.json() self.assertIsInstance(body, dict) self.assertIsInstance(body.get('history'), dict) self.assertIsInstance(body.get('number_truncated'), int) self.assertEqual(len(body), 2) self.assertEqual(body['number_truncated'], 0) history = body['history'] self.assertIsInstance(history.get('items'), list) self.assertEqual(len(history), 1) items = history['items'] self.assertEqual(len(items), 1) self.assertIsInstance(items[0], dict) item = items[0] self.assertIsInstance(item.get('id'), int) self.assertIsInstance(item.get('edited_by'), dict) self.assertIsInstance(item.get('edited_reason'), str) self.assertIsInstance(item.get('old_body'), str) self.assertIsInstance(item.get('new_body'), str) self.assertIsInstance(item.get('old_desc'), str) self.assertIsInstance(item.get('new_desc'), str) self.assertIsInstance(item.get('edited_at'), int) self.assertEqual(item['id'], hist_id) self.assertEqual(item['edited_reason'], 'testing') self.assertEqual(item['old_body'], 'older raw') self.assertEqual(item['new_body'], 'body') self.assertEqual(item['old_desc'], 'old desc') self.assertEqual(item['new_desc'], 'desc') edited_by = item['edited_by'] self.assertIsInstance(edited_by.get('id'), int) self.assertIsInstance(edited_by.get('username'), str) self.assertEqual(edited_by['id'], user_id)