Skip to content

Commit

Permalink
Rename test configs to avoid .gitignore
Browse files Browse the repository at this point in the history
  • Loading branch information
penguintutor committed Aug 31, 2022
1 parent c35b8b9 commit 5cae051
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 86 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ For more details see:
To install the RPI ws281x library:

pip3 install rpi_ws281x

To install the Argon hash algorithm

sudo apt install python3-argon2

To install the Flask CSRF protection

pip3 install Flask-WTF

To be able to run the tests

To be able to run the tests

sudo apt install python3-pytest


Expand Down Expand Up @@ -72,9 +74,9 @@ For more information see: [Penguin Tutor guide to starting programs automaticall

# Security

The pixel server is designed to support varying levels of security depending upon your system requirements.
The pixel server is designed to support varying levels of security depending upon your system requirements.

If used on a private only network then it can be configured for network address authentication.
If used on a private only network then it can be configured for network address authentication.

If allowing incoming connections from the Internet then it is recommended that user authentication is enabled and it is configured through SSL. The configuration below is based on using Nginx as a reverse proxy to provide HTTPS using a LetsEncrypt certificate.

Expand Down Expand Up @@ -103,7 +105,7 @@ ln -s to /etc/nginx/sites-enabled


Add the following in a location file (this assumes using /rpi1/ as the route
for this particular server.
for this particular server.

location /rpi1/ {
proxy_set_header X-Real-IP $remote_addr;
Expand Down Expand Up @@ -208,7 +210,7 @@ SK6812W_STRIP
Controls authentication. Can have one or more of the following, which can be a single IP address, or a network subnet, multiple addresses or network subnets (comma seperated) or 0.0.0.0 (all addresses)
Multiple entries will be appended to the access.

proxy_server =
proxy_server =
Any addresses in this range will be treated as proxy servers.
If the proxy server has X-Real-IP set then that will be used instead of the local ip address of the server. Warning if that is not a proxy server then this
could be a security risk (in terms of allowing non authenticated logins). Cannot be 0.0.0.0 (everywhere is a proxy doesn't make sense) - normally this will be specific IP address rather than range.
Expand Down Expand Up @@ -265,4 +267,4 @@ If upgrading from a version prior to July 2022 then you may need to create a new
Currently supports limited automated testing based around the authentication. This is achieved using:
py.test-3

Manual testing is required for all other functions.
Manual testing is required for all other functions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions tests/configs/auth_test.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Authentication rules for Pixel Server
# Following addresses can access without authentication
network_allow_always = 127.0.0.1
# Following allowed, but need to authenticate
# 0.0.0.0 = all addresses
network_allow_auth = 0.0.0.0
1 change: 1 addition & 0 deletions tests/configs/customlight_test.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#008000
File renamed without changes.
12 changes: 12 additions & 0 deletions tests/configs/pixelserver_test.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Configuration file for pixel-server
# Overrides entries in defaults.cfg

ledcount=44
gpiopin=18
ledfreq=800000
leddma=5
ledmaxbrightness=50
ledinvert=False
ledchannel=0
striptype=GRB
algorithm=Argon2
File renamed without changes.
4 changes: 4 additions & 0 deletions tests/configs/users_test.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
admin:$argon2id$v=19$m=102400,t=2,p=8$0ZzMvxnNwvxePMp+y7hpfA$rCupS+lnWHUdEeIVkUHAGQ:Admin user:admin::
stduser1:$argon2id$v=19$m=102400,t=2,p=8$QHpYDjnCGTsoxbRbxST34w$AW5TCq3vw4S+NujD8EUH9Q::standard::
adminuser1:$5$1883d31e1d394719b2eab0b9b2c786bc$743be7524ea18ca3fbc53333d0cec4cfd20e115045ddb455f30d1bcf3df2621d:Admin user real name:admin:[email protected]:Admin user sha256
stduser2:$5$1948a2047f5743c4a64bde92919d3eec$25670be86447039a5e126fc8acaac5e4ee4bd7805fcb493074ea9877be03088c:Standard user real name:standard:[email protected]:Standard user sha256
46 changes: 23 additions & 23 deletions tests/functional/test_flask_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,25 @@
# use csrf_enable = False in create_app() for any posts

# For log debugging use debug=True in create_app()
# then using logging.debug
# then using logging.debug

# That is tested separately outside of this. See TESTS.md for more details

# default configs use alternative as required for each test
default_config_filename = "tests/configs/defaults.cfg"
custom_config_filename = "tests/configs/pixelserver.cfg"
custom_light_config_filename = "tests/configs/customlight.cfg"
auth_config_filename = "tests/configs/auth.cfg"
auth_users_filename = "tests/configs/users.cfg"
default_config_filename = "tests/configs/defaults_test.cfg"
custom_config_filename = "tests/configs/pixelserver_test.cfg"
custom_light_config_filename = "tests/configs/customlight_test.cfg"
auth_config_filename = "tests/configs/auth_test.cfg"
auth_users_filename = "tests/configs/users_test.cfg"

# default use _log_filename which uses directory factory
log_filename = "pixelserver.log"

# special configs
# No network_allow_always (no guest)
auth_config_noguest = "tests/configs/auth-noguest.cfg"
auth_config_none = "tests/configs/auth-allownone.cfg"
auth_config_proxy = "tests/configs/auth-proxy.cfg"
auth_config_noguest = "tests/configs/auth-noguest_test.cfg"
auth_config_none = "tests/configs/auth-allownone_test.cfg"
auth_config_proxy = "tests/configs/auth-proxy_test.cfg"


def tmp_dir_setup (tmp_path_factory):
Expand Down Expand Up @@ -53,43 +53,43 @@ def test_index_2():
response = test_client.get('/')
assert response.status_code == 302
assert (response.location == "http://localhost/login") or (response.location == "/login")

# Not allowed
def test_index_3():
app = create_app(auth_config_none, auth_users_filename, _log_filename, debug=True)
with app.test_client() as test_client:
response = test_client.get('/')
assert response.status_code == 302
assert (response.location == "http://localhost/invalid") or (response.location == "/invalid")

# Test proxy- authentication required
def test_index_4():
app = create_app(auth_config_proxy, auth_users_filename, _log_filename, debug=True)
logging.debug ("*TEST Test proxy - login required")
with app.test_client() as test_client:
response = test_client.get('/',
response = test_client.get('/',
headers={'X-Real_IP': '192.168.0.22'}
)
assert response.status_code == 302
assert (response.location == "http://localhost/login") or (response.location == "/login")

# Test proxy - address not allowed
def test_index_5():
app = create_app(auth_config_proxy, auth_users_filename, _log_filename, debug=True)
logging.info ("*TEST Test proxy - invalid")
with app.test_client() as test_client:
response = test_client.get('/',
response = test_client.get('/',
headers={'X-Real_IP': '10.5.5.1'}
)
assert response.status_code == 302
assert response.location == "http://localhost/invalid"

# Test proxy - no login required
def test_index_5():
app = create_app(auth_config_proxy, auth_users_filename, _log_filename, debug=True)
logging.info ("*TEST Test proxy - guest login")
with app.test_client() as test_client:
response = test_client.get('/',
response = test_client.get('/',
headers={'X-Real_IP': '192.168.3.7'}
)
assert response.status_code == 200
Expand All @@ -102,11 +102,11 @@ def test_login_page_2():
response = test_client.get('/login')
assert response.status_code == 200
assert 'Please login to access' in str(response.data)

def test_login_success_1():
app = create_app(auth_config_filename, auth_users_filename, _log_filename, csrf_enable=False, debug=True)
with app.app_context():
test_client = app.test_client()
test_client = app.test_client()
response = test_client.post("/login", data={
"username": "admin",
"password": "pixel1login2",
Expand All @@ -117,30 +117,30 @@ def test_login_success_1():
def test_login_fail_1():
app = create_app(auth_config_filename, auth_users_filename, _log_filename, csrf_enable=False, debug=True)
with app.app_context():
test_client = app.test_client()
test_client = app.test_client()
response = test_client.post("/login", data={
"username": "admin",
"password": "pixel",
}, follow_redirects=True)
assert response.status_code == 200
assert 'Invalid login attempt' in str(response.data)

# invalid characters in username
def test_login_fail_2():
app = create_app(auth_config_filename, auth_users_filename, _log_filename, csrf_enable=False, debug=True)
with app.app_context():
test_client = app.test_client()
test_client = app.test_client()
response = test_client.post("/login", data={
"username": "adm<d>in",
"password": "pixel",
}, follow_redirects=True)
assert response.status_code == 200
assert 'Invalid login attempt' in str(response.data)

def test_login_fail_3():
app = create_app(auth_config_filename, auth_users_filename, _log_filename, csrf_enable=False, debug=True)
with app.app_context():
test_client = app.test_client()
test_client = app.test_client()
response = test_client.post("/login", data={
"username": "admin:noallowed",
"password": "pixel1login2",
Expand Down
44 changes: 22 additions & 22 deletions tests/functional/test_flask_passwords_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# use csrf_enable = False in create_app() for any posts

# For log debugging use debug=True in create_app()
# then using logging.debug
# then using logging.debug

# Users tmp_path_factory - files will be copied to:
#/tmp/pytest-of-<username>/pytest-current/log?/pixelserver.log
Expand All @@ -35,12 +35,12 @@
# name of config files - will be mapped to temp directory
# In tests use configs{} instead.
config_filenames = {
'default' : "defaults.cfg",
'custom' : "pixelserver.cfg",
'sha256' : "sha256.cfg",
'light' : "customlight.cfg",
'auth' : "auth.cfg",
'users' : "users.cfg"
'default' : "defaults_test.cfg",
'custom' : "pixelserver_test.cfg",
'sha256' : "sha256_test.cfg",
'light' : "customlight_test.cfg",
'auth' : "auth_test.cfg",
'users' : "users_test.cfg"
}


Expand All @@ -49,7 +49,7 @@
configs = {}

def tmp_dir_setup (tmp_path_factory):
global _log_directory, _log_filename, _config_directory
global _log_directory, _log_filename, _config_directory
_log_directory = str(tmp_path_factory.mktemp("log"))
_log_filename = _log_directory + "/" + log_filename
_config_directory = str(tmp_path_factory.mktemp("config"))
Expand All @@ -58,7 +58,7 @@ def tmp_dir_setup (tmp_path_factory):
configs[key] = _config_directory + "/" + value
# copy existing file to new location
shutil.copyfile(_config_src_directory + value, configs[key])


# Setup path factory and empty user file
def test_setup_factory(tmp_path_factory):
Expand Down Expand Up @@ -109,7 +109,7 @@ def test_password_changer_1():
assert 'Password changed' in str(response.data)
# Swap to new password
current_password = new_password
# logout
# logout
response = test_client.get('/logout')
assert response.status_code == 200
assert "Logged out" in str(response.data)
Expand All @@ -121,7 +121,7 @@ def test_password_changer_1():
}, follow_redirects=True)
assert response.status_code == 200
eval_string = '<button type="button" id="profilebutton" onclick="profile()">{}</button>'.format(username)
assert eval_string in str(response.data)
assert eval_string in str(response.data)
# Restore original password
new_password = first_password
response = test_client.post("/password", data={
Expand All @@ -134,7 +134,7 @@ def test_password_changer_1():
assert 'Password changed' in str(response.data)
# Swap to new password
current_password = new_password
# logout
# logout
response = test_client.get('/logout')
assert response.status_code == 200
assert "Logged out" in str(response.data)
Expand All @@ -146,7 +146,7 @@ def test_password_changer_1():
}, follow_redirects=True)
assert response.status_code == 200
eval_string = '<button type="button" id="profilebutton" onclick="profile()">{}</button>'.format(username)
assert eval_string in str(response.data)
assert eval_string in str(response.data)


# Test with long passwords (10 x)
Expand Down Expand Up @@ -192,7 +192,7 @@ def test_password_change_long_1():
assert 'Password changed' in str(response.data)
# Swap to new password
current_password = new_password
# logout
# logout
response = test_client.get('/logout')
assert response.status_code == 200
assert "Logged out" in str(response.data)
Expand All @@ -204,7 +204,7 @@ def test_password_change_long_1():
}, follow_redirects=True)
assert response.status_code == 200
eval_string = '<button type="button" id="profilebutton" onclick="profile()">{}</button>'.format(username)
assert eval_string in str(response.data)
assert eval_string in str(response.data)
# Restore original password
new_password = first_password
response = test_client.post("/password", data={
Expand All @@ -217,7 +217,7 @@ def test_password_change_long_1():
assert 'Password changed' in str(response.data)
# Swap to new password
current_password = new_password
# logout
# logout
response = test_client.get('/logout')
assert response.status_code == 200
assert "Logged out" in str(response.data)
Expand All @@ -229,7 +229,7 @@ def test_password_change_long_1():
}, follow_redirects=True)
assert response.status_code == 200
eval_string = '<button type="button" id="profilebutton" onclick="profile()">{}</button>'.format(username)
assert eval_string in str(response.data)
assert eval_string in str(response.data)

# check with passwords that are too short
def test_short_passwords_1():
Expand Down Expand Up @@ -313,7 +313,7 @@ def test_noletter_passwords_1():
def _create_valid_password (max_chars = 20):
# First create totally random string
password = ''.join(random.choice(allowed_chars) for i in range(random.randint(8,max_chars)))
# strip spaces from end
# strip spaces from end
password = password.strip()
# If no alpha add one to end
if not _has_lowercase(password):
Expand All @@ -326,9 +326,9 @@ def _create_valid_password (max_chars = 20):
while (len(password) < 8):
password += random.choice(string.printable)
return password



def _has_digit (string):
for i in list(string):
if i.isdigit():
Expand All @@ -340,7 +340,7 @@ def _has_lowercase (string):
if i.islower():
return True
return False

def _has_uppercase (string):
for i in list(string):
if i.isupper():
Expand Down
Loading

0 comments on commit 5cae051

Please sign in to comment.