2017-10-29 15:08:00 +00:00
|
|
|
#!/usr/bin/env python
|
2018-03-04 20:49:56 +00:00
|
|
|
# coding: utf-8
|
2017-10-29 15:08:00 +00:00
|
|
|
#
|
|
|
|
# This file is part of Supysonic.
|
|
|
|
# Supysonic is a Python implementation of the Subsonic server API.
|
|
|
|
#
|
2018-01-11 22:08:53 +00:00
|
|
|
# Copyright (C) 2017-2018 Alban 'spl0k' Féron
|
|
|
|
# 2017 Óscar García Amor
|
2017-10-29 15:08:00 +00:00
|
|
|
#
|
|
|
|
# Distributed under terms of the GNU AGPLv3 license.
|
|
|
|
|
|
|
|
import base64
|
2018-01-21 21:02:32 +00:00
|
|
|
import flask.json
|
2017-10-29 15:08:00 +00:00
|
|
|
|
|
|
|
from xml.etree import ElementTree
|
|
|
|
|
2017-11-17 22:26:25 +00:00
|
|
|
from ..testbase import TestBase
|
2018-01-11 22:08:53 +00:00
|
|
|
from ..utils import hexlify
|
2017-10-29 15:08:00 +00:00
|
|
|
|
2017-11-17 22:26:25 +00:00
|
|
|
class ApiSetupTestCase(TestBase):
|
2017-11-27 21:30:13 +00:00
|
|
|
__with_api__ = True
|
2017-10-29 15:08:00 +00:00
|
|
|
|
2018-01-11 22:08:53 +00:00
|
|
|
def setUp(self):
|
|
|
|
super(ApiSetupTestCase, self).setUp()
|
|
|
|
self._patch_client()
|
|
|
|
|
2017-10-29 15:08:00 +00:00
|
|
|
def __basic_auth_get(self, username, password):
|
2018-01-11 22:08:53 +00:00
|
|
|
hashed = base64.b64encode('{}:{}'.format(username, password).encode('utf-8'))
|
|
|
|
headers = { 'Authorization': 'Basic ' + hashed.decode('utf-8') }
|
2017-10-29 15:08:00 +00:00
|
|
|
return self.client.get('/rest/ping.view', headers = headers, query_string = { 'c': 'tests' })
|
|
|
|
|
|
|
|
def __query_params_auth_get(self, username, password):
|
|
|
|
return self.client.get('/rest/ping.view', query_string = { 'c': 'tests', 'u': username, 'p': password })
|
|
|
|
|
|
|
|
def __query_params_auth_enc_get(self, username, password):
|
2018-01-11 22:08:53 +00:00
|
|
|
return self.__query_params_auth_get(username, 'enc:' + hexlify(password))
|
2017-10-29 15:08:00 +00:00
|
|
|
|
|
|
|
def __form_auth_post(self, username, password):
|
|
|
|
return self.client.post('/rest/ping.view', data = { 'c': 'tests', 'u': username, 'p': password })
|
|
|
|
|
|
|
|
def __form_auth_enc_post(self, username, password):
|
2018-01-11 22:08:53 +00:00
|
|
|
return self.__form_auth_post(username, 'enc:' + hexlify(password))
|
2017-10-29 15:08:00 +00:00
|
|
|
|
|
|
|
def __test_auth(self, method):
|
|
|
|
# non-existent user
|
|
|
|
rv = method('null', 'null')
|
|
|
|
self.assertEqual(rv.status_code, 401)
|
|
|
|
self.assertIn('status="failed"', rv.data)
|
|
|
|
self.assertIn('code="40"', rv.data)
|
|
|
|
|
|
|
|
# user request with bad password
|
|
|
|
rv = method('alice', 'wrong password')
|
|
|
|
self.assertEqual(rv.status_code, 401)
|
|
|
|
self.assertIn('status="failed"', rv.data)
|
|
|
|
self.assertIn('code="40"', rv.data)
|
|
|
|
|
|
|
|
# user request
|
|
|
|
rv = method('alice', 'Alic3')
|
|
|
|
self.assertEqual(rv.status_code, 200)
|
|
|
|
self.assertIn('status="ok"', rv.data)
|
|
|
|
|
|
|
|
def test_auth_basic(self):
|
|
|
|
# No auth info
|
|
|
|
rv = self.client.get('/rest/ping.view?c=tests')
|
2018-02-25 10:39:26 +00:00
|
|
|
self.assertEqual(rv.status_code, 400)
|
2017-10-29 15:08:00 +00:00
|
|
|
self.assertIn('status="failed"', rv.data)
|
2018-02-25 10:39:26 +00:00
|
|
|
self.assertIn('code="10"', rv.data)
|
2017-10-29 15:08:00 +00:00
|
|
|
|
|
|
|
self.__test_auth(self.__basic_auth_get)
|
|
|
|
|
|
|
|
# Shouldn't accept 'enc:' passwords
|
2018-01-11 22:08:53 +00:00
|
|
|
rv = self.__basic_auth_get('alice', 'enc:' + hexlify('Alic3'))
|
2017-10-29 15:08:00 +00:00
|
|
|
self.assertEqual(rv.status_code, 401)
|
|
|
|
self.assertIn('status="failed"', rv.data)
|
|
|
|
self.assertIn('code="40"', rv.data)
|
|
|
|
|
|
|
|
def test_auth_query_params(self):
|
|
|
|
self.__test_auth(self.__query_params_auth_get)
|
|
|
|
self.__test_auth(self.__query_params_auth_enc_get)
|
|
|
|
|
|
|
|
def test_auth_post(self):
|
|
|
|
self.__test_auth(self.__form_auth_post)
|
|
|
|
self.__test_auth(self.__form_auth_enc_post)
|
|
|
|
|
|
|
|
def test_required_client(self):
|
|
|
|
rv = self.client.get('/rest/ping.view', query_string = { 'u': 'alice', 'p': 'Alic3' })
|
|
|
|
self.assertIn('status="failed"', rv.data)
|
|
|
|
self.assertIn('code="10"', rv.data)
|
|
|
|
|
|
|
|
rv = self.client.get('/rest/ping.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
|
|
|
self.assertIn('status="ok"', rv.data)
|
|
|
|
|
|
|
|
def test_format(self):
|
|
|
|
args = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' }
|
|
|
|
rv = self.client.get('/rest/getLicense.view', query_string = args)
|
|
|
|
self.assertEqual(rv.status_code, 200)
|
|
|
|
self.assertTrue(rv.mimetype.endswith('/xml')) # application/xml or text/xml
|
|
|
|
self.assertIn('status="ok"', rv.data)
|
|
|
|
xml = ElementTree.fromstring(rv.data)
|
|
|
|
self.assertIsNotNone(xml.find('./{http://subsonic.org/restapi}license'))
|
|
|
|
|
|
|
|
args.update({ 'f': 'json' })
|
|
|
|
rv = self.client.get('/rest/getLicense.view', query_string = args)
|
|
|
|
self.assertEqual(rv.status_code, 200)
|
|
|
|
self.assertEqual(rv.mimetype, 'application/json')
|
2018-01-21 21:02:32 +00:00
|
|
|
json = flask.json.loads(rv.data)
|
2017-10-29 15:08:00 +00:00
|
|
|
self.assertIn('subsonic-response', json)
|
|
|
|
self.assertEqual(json['subsonic-response']['status'], 'ok')
|
|
|
|
self.assertIn('license', json['subsonic-response'])
|
|
|
|
|
|
|
|
args.update({ 'f': 'jsonp' })
|
|
|
|
rv = self.client.get('/rest/getLicense.view', query_string = args)
|
2018-01-27 14:18:44 +00:00
|
|
|
self.assertEqual(rv.mimetype, 'application/json')
|
2018-01-21 21:02:32 +00:00
|
|
|
json = flask.json.loads(rv.data)
|
2017-10-29 15:08:00 +00:00
|
|
|
self.assertIn('subsonic-response', json)
|
|
|
|
self.assertEqual(json['subsonic-response']['status'], 'failed')
|
|
|
|
self.assertEqual(json['subsonic-response']['error']['code'], 10)
|
|
|
|
|
|
|
|
args.update({ 'callback': 'dummy_cb' })
|
|
|
|
rv = self.client.get('/rest/getLicense.view', query_string = args)
|
|
|
|
self.assertEqual(rv.status_code, 200)
|
|
|
|
self.assertEqual(rv.mimetype, 'application/javascript')
|
|
|
|
self.assertTrue(rv.data.startswith('dummy_cb({'))
|
|
|
|
self.assertTrue(rv.data.endswith('})'))
|
2018-01-21 21:02:32 +00:00
|
|
|
json = flask.json.loads(rv.data[9:-1])
|
2017-10-29 15:08:00 +00:00
|
|
|
self.assertIn('subsonic-response', json)
|
|
|
|
self.assertEqual(json['subsonic-response']['status'], 'ok')
|
|
|
|
self.assertIn('license', json['subsonic-response'])
|
|
|
|
|
|
|
|
def test_not_implemented(self):
|
|
|
|
# Access to not implemented endpoint
|
|
|
|
rv = self.client.get('/rest/not-implemented', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
|
|
|
self.assertEqual(rv.status_code, 501)
|
|
|
|
self.assertIn('status="failed"', rv.data)
|
|
|
|
self.assertIn('code="0"', rv.data)
|
|
|
|
|
|
|
|
rv = self.client.post('/rest/not-implemented', data = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
|
|
|
self.assertEqual(rv.status_code, 501)
|
|
|
|
self.assertIn('status="failed"', rv.data)
|
|
|
|
self.assertIn('code="0"', rv.data)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main()
|
|
|
|
|