Compare commits

...

88 commits

Author SHA1 Message Date
3b83ebf3fb Merge pull request 'survey-end' (#211) from survey-end into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #211
2021-07-30 09:04:42 +00:00
a626e32cbe Remove apiurl so that no longer the data will get logged
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-30 11:01:19 +02:00
4c01e68264 Make a box that the study is finished 2021-07-30 11:00:02 +02:00
7026909c61 Merge pull request 'Remove logging of password and update privacy(fix #203)' (#210) from frontend/remove-log into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #210
2021-07-25 21:36:41 +00:00
d01a70f925 Updated licenses and privacy
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-25 23:36:05 +02:00
41143c361b Remove logging of password
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-25 23:27:49 +02:00
3f6b622088 Merge pull request 'backend/update-requirements' (#209) from backend/update-requirements into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #209
2021-07-24 22:19:50 +00:00
d5c6aad834 Updated dockerfile
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-25 00:19:26 +02:00
fe5b563139 Updated python requirements
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-25 00:15:05 +02:00
ae82024e94 Merge pull request 'infra/bumpversion' (#208) from infra/bumpversion into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #208
2021-07-24 22:07:26 +00:00
c5b595ad40 Updated some things for infrastructure
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-25 00:05:11 +02:00
8bb37bbc21 Updated to upstream
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-24 02:11:17 +02:00
74ca8d8973 Merge branch 'main' into infra/bumpversion 2021-07-24 02:08:39 +02:00
deecf9ccad Removed unused function
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-24 01:16:39 +02:00
94070d8f75 Merge pull request 'Update logger config and create a session usermapping (fix #178 and fix #188)' (#206) from frontend/logger-update into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #206
2021-07-23 23:15:34 +00:00
c52308e623 Update logger config and create a session usermapping
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-24 01:14:25 +02:00
d220f86cb8 Remove the input if someone typed the wrong password
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-24 01:10:40 +02:00
a97c95f762 Bumped version of mongodb 2021-07-24 01:08:17 +02:00
5816d4f914 Remove unused fontawesome usages
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-23 03:46:43 +02:00
617741218c Add things about privacy for the user
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-23 03:35:09 +02:00
a373ad4dce Merge pull request 'Fix various issues in the frontend (fix #197 & fix #192)' (#200) from frontend/fix-paste-errormessage into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #200
2021-07-22 23:07:18 +00:00
9f4e097e27 Merge branch 'main' into frontend/fix-paste-errormessage
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-23 01:05:32 +02:00
8e6a74d30c Added a bugfix in the backend
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-22 23:05:13 +00:00
d168b0c87e Add errormessage if username or password are not correct
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-23 01:00:14 +02:00
1d0f898fc9 Do not allow copy and paste in survey (fix #197) 2021-07-23 00:59:39 +02:00
90e77bf450 Clean up some things 2021-07-23 00:58:34 +02:00
31513f4824 Make it not possible to copy the password with css 2021-07-23 00:54:29 +02:00
a1a719088d Added some more options to requests-script
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-23 00:51:28 +02:00
85e484bf0b Renaming and autoformatting
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
- renamed the react files to jsx
- autoformat with vscode
2021-07-22 20:18:01 +02:00
e762032f00 Merge pull request 'frontend/refactoring' (#195) from frontend/refactoring into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #195
2021-07-22 18:03:20 +00:00
dcd4215efa Renamed lizenzen.js to Lizenzen.js
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 20:02:35 +02:00
52131aa3dd Refactoring..
All checks were successful
continuous-integration/drone/push Build is passing
- use STATES instead of multiple different variables
- add check if password is correct
-
2021-07-22 19:55:06 +02:00
fd205273fc Added content in license page
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-22 19:01:40 +02:00
9cf2c50d01 Added study button
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-22 17:10:35 +02:00
47166c6345 Merge pull request 'Check in the frontend if the username and password in the survey are correct (fix #179)' (#185) from frontend/check-username-pw-survey into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #185
2021-07-22 14:55:26 +00:00
396b45df67 Add text at the end of the study
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 16:54:24 +02:00
eaa4d8937a use property to show the value of the actual password 2021-07-22 16:53:57 +02:00
2f7d733591 Receive password and check if it's the same 2021-07-22 16:53:08 +02:00
f5e58ccb09 Merge branch 'main' into frontend/check-username-pw-survey
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 07:31:17 +02:00
ca49c0d0f1 Merge pull request 'Added content' (#187) from content into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #187
2021-07-22 05:30:32 +00:00
d1bc91bcb7 Added content
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 07:29:54 +02:00
58bd327377 Update some change password things..
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 05:20:37 +02:00
a6346d7496 Password validation works but password is not shown in generated password thing
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 04:44:31 +02:00
c1fce5bf4a Change api for random password
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 03:24:31 +02:00
7a930c20b6 Permissions for requests.sh
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-22 03:11:50 +02:00
130088756d Check if username is the same as in the current session 2021-07-22 03:11:28 +02:00
770e3e0285 Started implementing username and password check 2021-07-22 02:41:24 +02:00
e7407fd40b Refactoring and removing unused things 2021-07-22 02:40:58 +02:00
959912bd9b Refactored so that the studyEnd also has its own component 2021-07-22 02:40:17 +02:00
fbbdbd4332 Updated requests script
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-22 02:37:04 +02:00
117e63e189 Added requests script to not enter all the things always 2021-07-22 02:26:06 +02:00
f00bc19994 Add special character and numbers inside the password
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-22 00:02:57 +02:00
060f20d25c Merge pull request 'Add multiple subpages for the survey...' (#177) from frontend/survey-multiple-sites into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #177
2021-07-21 21:41:32 +00:00
1553f92adf Added multiple situations so the survey is more complete
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-21 23:41:10 +02:00
146b018ad1 Start logger when starting survey
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-21 22:38:31 +02:00
65fcf8e4ab Working things 2021-07-21 22:04:23 +02:00
cf481d42e1 Refactoring..
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-21 21:53:57 +02:00
c5788a00d2 Forceupdate things
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-21 21:33:16 +02:00
d162a4005d Merge pull request 'Refactored some things in the frontend' (#175) from frontend/buttons into main
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #175
2021-07-21 02:34:24 +00:00
d055e693aa Refactored some things in the frontend
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
- use button insted of inputfield
- make use of conditional rendering
2021-07-21 04:33:52 +02:00
1751a37511 Updated and removed some npm packages
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-21 04:26:23 +02:00
20da4043a8 Merge pull request 'frontend/refactoring' (#172) from frontend/refactoring into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #172
2021-07-21 00:23:40 +00:00
01296702d3 Merge pull request 'Removed last part from password as it's too long' (#171) from backend/change-pw into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #171
2021-07-21 00:23:11 +00:00
213dcc9197 Renaming some files.
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-21 02:22:40 +02:00
966304ac3a Refactored herosection so it is more consistent with other fiels 2021-07-21 02:21:40 +02:00
a56e8ccb5c Renamed behavior to study 2021-07-21 02:21:00 +02:00
2000072a34 Removed last part from password as it's too long
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-21 02:19:47 +02:00
d0d097d665 Changed nginx port as it won't work otherways :-)
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-21 00:17:20 +02:00
d03a6e4985 Merge pull request 'Added url for my server' (#167) from infra/urlfix into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #167
2021-07-20 21:55:52 +00:00
a0d8645593 Added url for my server
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-20 23:51:48 +02:00
008810151f Refactored some things
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-19 02:16:49 +02:00
a5b680d948 Merge pull request 'Added backend for the analytics stuff..' (#162) from analytics/backend-deployment into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #162
2021-07-18 22:00:20 +00:00
50b8d4f82e Added backend for the analytics stuff..
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-18 23:59:04 +02:00
9808c2509c Merge pull request 'Random passwords during study (fix #120)' (#159) from feature/random-password into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #159
2021-07-18 14:59:00 +00:00
c67da25cc9 Add generated password to frontend
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-18 16:58:02 +02:00
5e07b3b7dd Added some more words for password generator
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-17 01:45:29 +02:00
6da747d632 Add backend API to receive a random password 2021-07-17 01:45:11 +02:00
ecb06e812d Update branch with upstream changes
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-17 00:53:49 +02:00
c306acc97a Remove unused things
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-17 00:52:50 +02:00
8d7b5daa48 Merge pull request 'Logger works' (#160) from feature/logger-web into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #160
2021-07-16 21:39:21 +00:00
6ee3d16f74 Logger works
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-16 23:06:38 +02:00
f64406c74b Backend implementation for random passwords
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2021-07-16 04:00:01 +02:00
c9e987a28f Updated some things and logger starts only once
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-16 02:16:08 +02:00
0e222d3d52 Autoformatting all files
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-14 21:05:16 +02:00
816689acdf Test the behaviour of the prod-containers locally
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-14 17:13:03 +02:00
9aa573384b Fixing database error
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-14 00:46:51 +02:00
46ce8655f3 renamed some thigns
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2021-07-13 20:25:02 +02:00
b335a471cb Merge pull request 'Fix broken backend connection in prod build (fix #151)' (#152) from infra/backendconnection into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #152
2021-07-13 18:06:06 +00:00
52 changed files with 1008 additions and 2359 deletions

View file

@ -1 +1,2 @@
venv venv
src/database.db

View file

@ -4,6 +4,9 @@ WORKDIR /app
COPY requirements.txt . COPY requirements.txt .
RUN apt-get -y update
RUN apt-get -y install sqlite3
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
COPY /src . COPY /src .

View file

@ -6,6 +6,8 @@ RUN apt-get -y update && apt-get -y upgrade
COPY requirements.txt . COPY requirements.txt .
RUN apt-get -y install sqlite3
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
COPY /src . COPY /src .

View file

@ -1,3 +1,4 @@
autopep8==1.5.7
blinker==1.4 blinker==1.4
click==7.1.2 click==7.1.2
Deprecated==1.2.12 Deprecated==1.2.12
@ -16,11 +17,13 @@ MarkupSafe==1.1.1
passlib==1.7.4 passlib==1.7.4
pendulum==2.1.2 pendulum==2.1.2
py-buzz==1.0.3 py-buzz==1.0.3
pycodestyle==2.7.0
PyJWT==2.1.0 PyJWT==2.1.0
python-dateutil==2.8.1 python-dateutil==2.8.1
python-dotenv==0.17.1 python-dotenv==0.17.1
pytzdata==2020.1 pytzdata==2020.1
six==1.16.0 six==1.16.0
SQLAlchemy==1.4.15 SQLAlchemy==1.4.15
toml==0.10.2
Werkzeug==1.0.1 Werkzeug==1.0.1
wrapt==1.12.1 wrapt==1.12.1

View file

@ -5,6 +5,7 @@ import flask_sqlalchemy
import flask_praetorian import flask_praetorian
import flask_cors import flask_cors
import sys import sys
from password_util import get_random_password
db = flask_sqlalchemy.SQLAlchemy() db = flask_sqlalchemy.SQLAlchemy()
guard = flask_praetorian.Praetorian() guard = flask_praetorian.Praetorian()
@ -75,6 +76,12 @@ db.init_app(app)
# Initializes CORS so that the api_tool can talk to the example app # Initializes CORS so that the api_tool can talk to the example app
cors.init_app(app) cors.init_app(app)
# create database
# Add users for the example
with app.app_context():
db.create_all()
db.session.commit()
@app.route('/api/login', methods=['POST']) @app.route('/api/login', methods=['POST'])
def login(): def login():
@ -106,13 +113,20 @@ def refresh():
$ curl http://localhost:5000/api/refresh -X GET \ $ curl http://localhost:5000/api/refresh -X GET \
-H "Authorization: Bearer <your_token>" -H "Authorization: Bearer <your_token>"
""" """
print("refresh request") old_token = flask.request.get_data()
old_token = request.get_data()
new_token = guard.refresh_jwt_token(old_token) new_token = guard.refresh_jwt_token(old_token)
ret = {'access_token': new_token} ret = {'access_token': new_token}
return ret, 200 return ret, 200
@app.route('/api/username', methods=['GET'])
@flask_praetorian.auth_required
def get_username():
username = flask_praetorian.current_user().username
ret = {'username': username}
return ret, 200
@app.route('/api/protected') @app.route('/api/protected')
@flask_praetorian.auth_required @flask_praetorian.auth_required
def protected(): def protected():
@ -127,6 +141,13 @@ def protected():
return {'message': f'protected endpoint (allowed user {flask_praetorian.current_user().username})'} return {'message': f'protected endpoint (allowed user {flask_praetorian.current_user().username})'}
@app.route('/api/rcv_pw', methods=['GET'])
def get_password():
pw = get_random_password()
ret = {'random_password': pw}
return ret, 200
@app.route('/api/register', methods=['POST']) @app.route('/api/register', methods=['POST'])
def register(): def register():
req = flask.request.get_json(force=True) req = flask.request.get_json(force=True)
@ -152,6 +173,17 @@ def register():
return ret, 409 return ret, 409
@app.route('/api/protected/behavior', methods=['POST'])
@flask_praetorian.auth_required
def check_password_username():
req = flask.request.get_json(force=True)
token = guard.read_token_from_header()
extracted_token = guard.extract_jwt_token(token)
id_req = extracted_token['id']
ret = {'message': 'Top'}
return ret, 200
@app.route('/api/protected/umfrage', methods=['POST']) @app.route('/api/protected/umfrage', methods=['POST'])
@flask_praetorian.auth_required @flask_praetorian.auth_required
def survey(): def survey():
@ -215,7 +247,6 @@ def survey():
user_db.education = education user_db.education = education
user_db.skills = skills user_db.skills = skills
db.session.commit() db.session.commit()
print(req)
ret = {'message': 'Vielen Dank für das Ausfüllen der Umfrage.'} ret = {'message': 'Vielen Dank für das Ausfüllen der Umfrage.'}
return ret, 200 return ret, 200
else: else:
@ -224,14 +255,6 @@ def survey():
return ret, 400 return ret, 400
@app.route('/api/protected/behavior', methods=['POST'])
@flask_praetorian.auth_required
def check_password_username():
print("hallooo POST", file=sys.stderr)
ret = {'message': 'Top'}
return ret, 200
# Run the example # Run the example
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=debug, host=host, port=port) app.run(debug=debug, host=host, port=port)

View file

@ -0,0 +1,117 @@
from random import seed
from random import randint
import time
seed(int(time.time()))
def get_random_value(list_length):
random_select = randint(0, list_length)
return random_select
def get_random_password():
first_part = [
"Der Vogel",
"Die Ameise",
"Die Biene",
"Ein Mensch",
"Jemand",
"Der Hund",
"Der Kater",
]
second_part = [
"%",
"(",
")",
"$",
"+",
"!",
]
third_part = [
"frisst",
"küsst",
"begrüsst",
"besucht",
"beeinflusst",
"isst",
"findet",
"vergisst",
]
forth_part = [
"1 Vogel!",
"2 Vögel!",
"3 Vögel!",
"4 Vögel!",
"5 Vögel!",
"6 Vögel!",
"7 Vögel!",
"8 Vögel!",
"9 Vögel!",
"1 Mücke",
"2 Mücken!",
"3 Mücken!",
"4 Mücken!",
"5 Mücken!",
"6 Mücken!",
"7 Mücken!",
"8 Mücken!",
"9 Mücken!",
"1 Adler",
"2 Adler!",
"3 Adler!",
"4 Adler!",
"5 Adler!",
"6 Adler!",
"7 Adler!",
"8 Adler!",
"9 Adler!",
"1 Apfel",
"2 Äpfel!",
"3 Äpfel!",
"4 Äpfel!",
"5 Äpfel!",
"6 Äpfel!",
"7 Äpfel!",
"8 Äpfel!",
"9 Äpfel!",
"1 Birne",
"2 Birnen!",
"3 Birnen!",
"4 Birnen!",
"5 Birnen!",
"6 Birnen!",
"7 Birnen!",
"8 Birnen!",
"9 Birnen!",
"1 Biene",
"2 Bienen!",
"3 Bienen!",
"4 Bienen!",
"5 Bienen!",
"6 Bienen!",
"7 Bienen!",
"8 Bienen!",
"9 Bienen!",
"1 Gurke",
"2 Gurken!",
"3 Gurken!",
"4 Gurken!",
"5 Gurken!",
"6 Gurken!",
"7 Gurken!",
"8 Gurken!",
"9 Gurken!",
]
password = ""
password += str(first_part[get_random_value(len(first_part)-1)])
password += " " + str(second_part[get_random_value(len(second_part)-1)])
password += " " + str(third_part[get_random_value(len(third_part)-1)])
password += " " + str(forth_part[get_random_value(len(forth_part)-1)])
return password

View file

@ -1,14 +1,27 @@
version: '3.7' version: '3.7'
services: services:
frontend_bt: frontend-prod:
image: caminsha/bt-frontend image: caminsha/bt-frontend
container_name: frontend_bt_prod container_name: frontend-prod
ports: ports:
- 3000:3000 - 3000:80
backend-prod: backend-prod:
image: caminsha/bt-backend image: caminsha/bt-backend
container_name: backend_bt container_name: backend-prod
volumes:
- "./database.db:/app/database.db:z"
environment: environment:
DEBUG: "no" DEBUG: "no"
PORT: 5000 PORT: 5050
HOST: "0.0.0.0" HOST: "0.0.0.0"
behametrics-server:
image: registry.gitlab.com/behametrics/server:latest
container_name: "behametrics-server"
ports:
- 5000:5000
environment:
- MONGO_URI=mongodb://mongodb:27017/behametrics
mongodb:
image: mongo:4.0.25
container_name: "behametrics-mongo"
command: mongod --smallfiles

View file

@ -2,7 +2,7 @@ version: '3.7'
services: services:
frontend-dev: frontend-dev:
container_name: hello_world_client container_name: frontend-dev
build: build:
context: ./frontend context: ./frontend
dockerfile: Dockerfile dockerfile: Dockerfile
@ -14,7 +14,7 @@ services:
environment: environment:
- CHOKIDAR_USEPOLLING=true - CHOKIDAR_USEPOLLING=true
backend-dev: backend-dev:
container_name: backend_bt container_name: backend-dev
build: build:
context: ./backend context: ./backend
dockerfile: Dockerfile dockerfile: Dockerfile
@ -22,8 +22,19 @@ services:
volumes: volumes:
- ./backend/src:/app/ - ./backend/src:/app/
ports: ports:
- 5000:5000 - 5050:5050
environment: environment:
DEBUG: "yes" DEBUG: "yes"
PORT: 5000 PORT: 5050
HOST: "0.0.0.0" HOST: "0.0.0.0"
behametrics-server:
image: registry.gitlab.com/behametrics/server:latest
container_name: "behametrics-server"
ports:
- 5000:5000
environment:
- MONGO_URI=mongodb://mongodb:27017/behametrics
mongodb:
image: mongo:4.0.25
container_name: "behametrics-mongo"
command: mongod --smallfiles

View file

@ -10,9 +10,7 @@ server {
} }
location /api { location /api {
# include uwsgi_params; proxy_pass http://backend-prod:5050;
# uwsgi_pass http://backend-prod:5000;
proxy_pass http://backend-prod:5000;
} }
error_page 500 502 503 504 /50x.html; error_page 500 502 503 504 /50x.html;

File diff suppressed because it is too large Load diff

View file

@ -5,18 +5,11 @@
"dependencies": { "dependencies": {
"@behametrics/logger-web": "^3.1.1", "@behametrics/logger-web": "^3.1.1",
"@fortawesome/fontawesome-free": "^5.15.3", "@fortawesome/fontawesome-free": "^5.15.3",
"@react-hook/mouse-position": "^4.1.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"npm": "^7.19.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-form-with-constraints": "^0.18.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"react-token-auth": "^1.1.8", "react-token-auth": "^1.1.8"
"web-vitals": "^1.1.2"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
@ -42,5 +35,5 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"proxy": "http://localhost:5000" "proxy": "http://localhost:5050"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -28,10 +28,13 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>BA - Marco Camenzind</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript
>Diese Anwendung funktioniert leider nur mit JavaScript. Bitte aktivieren
JavaScript in den Einstellungen</noscript
>
<div id="root"></div> <div id="root"></div>
<!-- <!--
This HTML file is a template. This HTML file is a template.

View file

@ -40,6 +40,10 @@
color: var(--primary); color: var(--primary);
} }
a {
text-decoration: none;
}
a:hover:not(.navbar-logo) { a:hover:not(.navbar-logo) {
border-bottom: 4px dotted var(--secondary); border-bottom: 4px dotted var(--secondary);
} }
@ -51,21 +55,32 @@ a:hover:not(.navbar-logo) {
} }
h1 { h1 {
font-size: 5em; font-size: 4.5em;
margin: 0.7em auto; margin: 0.7em auto;
text-align: center;
} }
.sitePage h2 { .sitePage h2 {
font-size: 3.75em; font-size: 3.7em;
margin: 0.7em auto; margin: 0.7em auto;
} }
.sitePage h3 {
font-size: 2em;
margin: 0.5em auto;
}
.sitePage p { .sitePage p {
font-size: 1.5em; font-size: 1.5em;
max-width: 60%; max-width: 60%;
margin-bottom: 4vh; margin-bottom: 4vh;
} }
.sitePage ul li {
font-size: 1.5em;
margin-bottom: 0.7em;
}
.errorMessage { .errorMessage {
color: var(--error); color: var(--error);
max-width: 60%; max-width: 60%;
@ -77,3 +92,18 @@ h1 {
.bildnachweise { .bildnachweise {
font-size: 1.3em; font-size: 1.3em;
} }
.generated-password {
font-weight: bold;
user-select: none;
}
.study-finished {
background-color: var(--primary);
padding: 0.5em;
}
.study-finished > p {
color: var(--error);
font-size: 2em;
}

View file

@ -4,20 +4,17 @@ import "./App.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./components/pages/Home"; import Home from "./components/pages/Home";
import Ueber from "./components/pages/Ueber"; import Ueber from "./components/pages/Ueber";
import Lizenzen from "./components/pages/lizenzen"; import Lizenzen from "./components/pages/Lizenzen";
import Privacy from "./components/pages/Privacy"; import Privacy from "./components/pages/Privacy";
import Login from "./components/pages/Login"; import Login from "./components/pages/Login";
import Register from "./components/pages/Register"; import Register from "./components/pages/Register";
import Manual from "./components/pages/Manual"; import Manual from "./components/pages/Manual";
import Secret from "./components/pages/Secret";
import Umfrage from "./components/pages/Umfrage"; import Umfrage from "./components/pages/Umfrage";
import PrivateRoute from "./auth/PrivateRoute"; import PrivateRoute from "./auth/PrivateRoute";
import { useAuth } from "./auth/AuthProvider"; import Study from "./components/pages/Study";
import BehaviorNormal from "./components/pages/BehaviorNormal"; import Secret from "./components/pages/Secret";
function App() { function App() {
const [isLoggedIn] = useAuth();
isLoggedIn ? (document.title = isLoggedIn) : document.title = isLoggedIn;
return ( return (
<> <>
<Router> <Router>
@ -31,7 +28,7 @@ function App() {
<Route path="/register" component={Register} /> <Route path="/register" component={Register} />
<Route path="/manual" component={Manual} /> <Route path="/manual" component={Manual} />
<Route path="/ueber" component={Ueber} /> <Route path="/ueber" component={Ueber} />
<PrivateRoute path="/behavior" component={BehaviorNormal} /> <PrivateRoute path="/study" component={Study} />
<PrivateRoute path="/secret" component={Secret} /> <PrivateRoute path="/secret" component={Secret} />
<PrivateRoute path="/umfrage" component={Umfrage} /> <PrivateRoute path="/umfrage" component={Umfrage} />
</Switch> </Switch>

View file

@ -92,45 +92,6 @@
color: #b1b1b1; color: #b1b1b1;
} }
/* Social Icons */
.social-icon-link {
color: var(--forth);
font-size: 24px;
}
.social-media {
max-width: 1000px;
width: 100%;
}
.social-media-wrap {
display: flex;
justify-content: space-between;
align-items: center;
width: 99%;
max-width: 1000px;
margin: 40px auto 0 auto;
}
.social-icons {
display: flex;
justify-content: space-between;
align-items: center;
width: 240px;
}
.social-logo {
color: var(--forth);
justify-self: start;
margin-left: 20px;
cursor: pointer;
text-decoration: none;
font-size: 2rem;
display: flex;
align-self: center;
margin-bottom: 16px;
}
@media screen and (max-width: 820px) { @media screen and (max-width: 820px) {
.footer-links { .footer-links {
padding-top: 2rem; padding-top: 2rem;
@ -148,7 +109,4 @@
flex-direction: column; flex-direction: column;
} }
.social-media-wrap {
flex-direction: column;
}
} }

View file

@ -1,7 +1,6 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import "./Footer.css"; import "./Footer.css";
import "@fortawesome/fontawesome-free/css/all.css";
function Footer() { function Footer() {
return ( return (

View file

@ -1,7 +0,0 @@
import React from "react";
function AuthorDate() {
return <div></div>;
}
export default AuthorDate;

View file

@ -0,0 +1,16 @@
import React from "react";
import "../App.css";
import GeneratedPassword from "./GeneratedPassword";
export default function BehaviorNormal(props) {
return (
<>
<p>
Zu Beginn geht es darum, dass Sie ganz normal den Benutzernamen und das
Passwort eingeben. Verhalten Sie sich einfach so, als ob Sie sich
normalerweise anmelden.
</p>
<GeneratedPassword genPassword={props.genPassword} />
</>
);
}

View file

@ -0,0 +1,17 @@
import React from "react";
import "../App.css";
import GeneratedPassword from "./GeneratedPassword";
export default function BehaviorPhone(props) {
return (
<>
<p>
Im nächsten Schritt geht es darum, dass Sie während der Passworteingabe
telefonieren. Nehmen Sie hierzu Ihr Smartphone oder Telefon und stellen
Sie sich vor, dass Sie gerade am Telefonieren sind. Verwenden Sie bitte
kein Headset oder Ähnliches.
</p>
<GeneratedPassword genPassword={props.genPassword} />
</>
);
}

View file

@ -0,0 +1,16 @@
import React from "react";
import "../App.css";
import GeneratedPassword from "./GeneratedPassword";
export default function BehaviorStanding(props) {
return (
<>
<p>
In dieser Situation geht es darum, dass Sie das Passwort im Stehen
eingeben. Stehen Sie also vor den Computer und geben Sie den
Benutzernamen und das Passwort wie gewohnt ein.
</p>
<GeneratedPassword genPassword={props.genPassword} />
</>
);
}

View file

@ -0,0 +1,18 @@
import React from "react";
import "../App.css";
export default function BehaviorStudyEnd() {
return (
<>
<p>
Vielen Dank, dass Sie an der Studie teilgenommen haben. Sie helfen mir
mit Ihrer Teilnahme enorm für die Bachelorthesis weiter.
</p>
<p>
Damit ich möglichst aussagekräftige Ergebnisse erhalte, ist es für mich
wichtig, dass Sie mehrmals an der Studie teilnehmen. Daher bitte ich
Sie, dass Sie zu einem anderen Zeitpunkt die Studie wiederholen.
</p>
</>
);
}

View file

@ -0,0 +1,19 @@
import React from "react";
import "../App.css";
export default function BehaviorStudyInfo() {
return (
<>
<p>
Nachfolgend werden Sie einige Schritte durchlaufen, um ihre
Nutzerinteraktion messen zu können. Verwenden Sie hierbei jeweils ihren
Benutzernamen, welchen Sie bereits zuvor genutzt haben. Das Passwort
wird jeweils generiert.
</p>
<p>
Bitte klicken Sie auf weiter, um mit der Studie zu beginnen. Bitte lesen
Sie die jeweilige Aufgabe jeweils genau.
</p>
</>
);
}

View file

@ -31,6 +31,12 @@
font-size: 1.3em; font-size: 1.3em;
} }
.btn--full {
padding: 12px 26px;
margin: 0 auto;
font-size: 1.5em;
}
.btn--large:hover, .btn--large:hover,
.btn--medium:hover { .btn--medium:hover {
transition: all 0.3s ease-out; transition: all 0.3s ease-out;

View file

@ -4,7 +4,7 @@ import { Link } from "react-router-dom";
const STYLES = ["btn--primary", "btn--outline"]; const STYLES = ["btn--primary", "btn--outline"];
const SIZES = ["btn--medium", "btn--large"]; const SIZES = ["btn--medium", "btn--large", "btn--full"];
export const Button = ({ export const Button = ({
children, children,
type, type,

View file

@ -0,0 +1,13 @@
import React from "react";
import "../App.css";
export default function GeneratedPassword(props) {
return (
<>
<p>
Das Passwort für diese Situation lautet:{" "}
<span className="generated-password">{props.genPassword}</span>
</p>
</>
);
}

View file

@ -2,22 +2,23 @@ import React from "react";
import "../App.css"; import "../App.css";
import { Button } from "./Button"; import { Button } from "./Button";
import "./HeroSection.css"; import "./HeroSection.css";
import "@fortawesome/fontawesome-free/css/all.css";
import { useAuth } from "../auth/AuthProvider"; import { useAuth } from "../auth/AuthProvider";
import StudyFinished from "./StudyFinished";
function HeroSection() { export default function HeroSection() {
const [isLoggedIn] = useAuth(); const [isLoggedIn] = useAuth();
return ( return (
<div className="hero-container"> <div className="hero-container">
<h1>Herzlich Willkommen</h1> <h1>Herzlich Willkommen</h1>
<StudyFinished />
<div className="hero-btns"> <div className="hero-btns">
{isLoggedIn ? ( {isLoggedIn ? (
<Button <Button
className="btns" className="btns"
buttonStyle="btn--primary" buttonStyle="btn--primary"
buttonSize="btn--large" buttonSize="btn--large"
newTo="behavior" newTo="study"
> >
Zur Studie Zur Studie
</Button> </Button>
@ -53,5 +54,3 @@ function HeroSection() {
</div> </div>
); );
} }
export default HeroSection;

View file

@ -6,6 +6,7 @@ import "@fortawesome/fontawesome-free/css/all.css";
function Navbar() { function Navbar() {
const [click, setClick] = useState(false); const [click, setClick] = useState(false);
// eslint-disable-next-line
const [button, setButton] = useState(true); const [button, setButton] = useState(true);
const handleClick = () => setClick(!click); const handleClick = () => setClick(!click);
@ -43,6 +44,17 @@ function Navbar() {
Startseite Startseite
</Link> </Link>
</li> </li>
{isLoggedIn && (
<li className="nav-item">
<Link
to="/study"
className="nav-links"
onClick={closeMobileMenu}
>
Studie
</Link>
</li>
)}
<li className="nav-item"> <li className="nav-item">
<Link to="/Ueber" className="nav-links" onClick={closeMobileMenu}> <Link to="/Ueber" className="nav-links" onClick={closeMobileMenu}>
Über Über

View file

@ -0,0 +1,11 @@
import React from "react";
import "../App.css"
export default function StudyFinished() {
return (
<div className="study-finished">
<p>Die Studie wurde beendet.</p>
<p>Vielen Dank für die Teilnahme an der Studie</p>
</div>
);
}

View file

@ -1,120 +0,0 @@
import React, { useEffect, useState} from "react";
import "../../App.css";
import Footer from "../../Footer";
import { Logger } from "@behametrics/logger-web";
import { useAuth } from "../../auth/AuthProvider";
import InputField from "../InputField";
import SubmitField from "../SubmitField";
export default function BehaviorNormal() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleUsernameChange = (e) => {
setUsername(e.target.value);
};
const handlePasswordChange = (e) => {
setPassword(e.target.value);
};
const handleOnCopyEvent = (e) => {
e.preventDefault();
console.log("copy not allowed");
return false;
};
const handleOnPasteEvent = (e) => {
e.preventDefault();
console.log("paste not allowed");
return false;
};
const onSubmitClick = (e) => {
e.preventDefault();
let opts = {
username: username,
password: password,
};
fetch("/api/protected/behavior", {
method: "post",
body: JSON.stringify(opts),
}).then((response) => {
if (response.status === 401) {
response.json().then((resp) => {
console.log("nicht so wirklich gut");
// setErrorMessage(resp.message);
});
} else {
response.json().then((token) => {
console.log("Alles gut :-)");
});
}
});
};
let logger = new Logger({
//inputs: ["cursor", "wheel", "keyboard", "touch"],
inputs: ["keyboard"],
// logToConsole: true,
});
logger.init();
let [isLoggedIn] = useAuth();
useEffect(() => {
document.title = `${isLoggedIn}`;
if (isLoggedIn === false) {
logger.stop();
} else {
logger.start();
}
});
return (
<>
<div className="sitePage">
<h1>Studie</h1>
<p>
Nachfolgend werden Sie einige Schritte durchlaufen, um ihre
Nutzerinteraktion messen zu können. Verwenden Sie hierbei jeweils
ihren Benutzernamen, welchen Sie bereits zuvor genutzt haben. Das
Passwort wird jeweils generiert.
</p>
<p>
Zu Beginn geht es darum, dass Sie ganz normal den Benutzernamen und
das Passwort eingeben. Verhalten Sie sich einfach so, als ob Sie sich
normalerweise anmelden.
</p>
<p onCopy={handleOnCopyEvent}>
Das Passwort für diese Situation lautet: abcdefgeh
</p>
<form action="#">
<InputField
LabelName="Benutzername"
onChange={handleUsernameChange}
InputType="text"
InputName="Benutzername"
InputPlaceHolder="Benutzername"
onCopy={handleOnCopyEvent}
onPaste={handleOnPasteEvent}
/>
<InputField
LabelName="Passwort"
onChange={handlePasswordChange}
InputType="password"
InputName="Passwort"
InputPlaceHolder="Benutzername"
onCopy={handleOnCopyEvent}
onPaste={handleOnPasteEvent}
/>
<SubmitField
LabelName="Weiter zur nächsten Situation"
InputValue="next-situation"
InputName="Weiter"
onClick={onSubmitClick}
/>
</form>
</div>
<Footer />
</>
);
}

View file

@ -0,0 +1,95 @@
import React from "react";
import "../../App.css";
import Footer from "../../Footer";
export default function Lizenzen() {
return (
<>
<div className="sitePage license">
<h1>Lizenzen und Bildnachweise</h1>
<p>
Nachfolgend sollen die verwendeten Bibliotheken inklusive der Lizenz
aufgeführt werden. Neben den Bibliotheken sollen vorallem auch
Bildnachweise notiert werden.
</p>
<h2>Verwendete Bibliotheken</h2>
<h3>Frontend</h3>
<ul>
<li>
ReactJS (MIT-Lizenz):{" "}
<a href="https://github.com/facebook/react">
https://github.com/facebook/react
</a>{" "}
</li>
<li>
Behametrics Web-Logger (MIT-Lizenz):{" "}
<a href="https://gitlab.com/behametrics/logger-web">
https://gitlab.com/behametrics/logger-web
</a>
</li>
<li>
Fortawesome Icons (CC-BY-4.0):{" "}
<a href="https://github.com/FortAwesome/Font-Awesome">
https://github.com/FortAwesome/Font-Awesome
</a>
</li>
<li>
React-Token-Auth (ISC-Lizenz):{" "}
<a href="https://github.com/obabichev/react-token-auth">
https://github.com/obabichev/react-token-auth
</a>
</li>
<li>
react-router-dom (MIT-Lizenz)
<a href="https://github.com/ReactTraining/react-router">
https://github.com/ReactTraining/react-router
</a>
</li>
</ul>
<h3>Backend</h3>
<ul>
<li>
Flask (BSD-3-Lizenz):{" "}
<a href="https://github.com/pallets/flask/">
https://github.com/pallets/flask/
</a>
</li>
<li>
flask-sqlalchemy (BSD-3-Lizenz):{" "}
<a href="https://github.com/pallets/flask-sqlalchemy">
https://github.com/pallets/flask-sqlalchemy
</a>
</li>
<li>
flask-praetorian (MIT-Lizenz):{" "}
<a href="https://github.com/dusktreader/flask-praetorian">
https://github.com/dusktreader/flask-praetorian
</a>
</li>
<li>
Flask-CORS (MIT-Lizenz):{" "}
<a href="https://github.com/corydolphin/flask-cors">
https://github.com/corydolphin/flask-cors
</a>
</li>
<li>
Behametrics Serverimplementierung (MIT-Lizenz):{" "}
<a href="https://gitlab.com/behametrics/server">
https://gitlab.com/behametrics/server
</a>
</li>
</ul>
<h2>Bildnachweise</h2>
<ul className="bildnachweise">
<li>
Originalbild für die Startseite:{" "}
<a href="https://pixabay.com/illustrations/virtual-identity-digital-identity-69996/">
https://pixabay.com/illustrations/virtual-identity-digital-identity-69996/
</a>
</li>
</ul>
</div>
<Footer />
</>
);
}

View file

@ -70,7 +70,7 @@ export default function Login() {
</form> </form>
) : ( ) : (
<> <>
<Redirect to="/behavior" /> <Redirect to="/study" />
</> </>
)} )}
</div> </div>

View file

@ -1,14 +0,0 @@
import React from "react";
import "../../App.css";
import Footer from "../../Footer";
export default function Manual() {
return (
<>
<div className="sitePage">
<h1> Anleitung / Bedienungshinweise</h1>
</div>
<Footer />
</>
);
}

View file

@ -0,0 +1,58 @@
import React from "react";
import { Link } from "react-router-dom";
import "../../App.css";
import Footer from "../../Footer";
export default function Manual() {
return (
<>
<div className="sitePage">
<h1> Anleitung / Bedienungshinweise</h1>
<p>
Vielen Dank für Ihr Interesse an meiner Bachelorthesis. Falls Sie noch
grundlegende Informationen benötigen, können Sie diese{" "}
<Link to="ueber">hier</Link> genauer anschauen. Hier geht es darum,
dass ich Ihnen eine kurze Anleitung zur Verfügung stelle und erkäre
wie das ganze funktioniert.
</p>
<h2>Neu hier</h2>
<p>
Bei Besuchern, die das erste Mal hier sind, geht es um zwei Dinge.
Erstens müssen sich diese registrieren und zweitens sollte eine
Umfrage durchgeführt werden. Diese Umfrage dient dazu, dass ich eine
grobe Übersicht habe, welche Personengruppen teilgenommen haben. Für
die Registrierung klicken Sie oben rechts einfach auf registieren. Sie
müssen dann einen Nutzernamen und ein Passwort eingeben. Schauen Sie
darauf, dass Sie sich den Benutzernamen und das Passwort merken
können. Es gibt keine Möglichkeit, das Passwort oder den Benutzernamen
zurückzusetzen. Nach der Registrierung landen Sie auf einer
Umfrageseite. Füllen Sie die Fragen wahrheitsgemäss aus und klicken
Sie danach auf "Umfrage abschicken". Nachdem die Umfrage durchgeführt
wurde, können Sie an der Studie teilnehmen, indem Sie auf den Button
"Studie starten" klicken. Folgen Sie danach den Anweisungen gemäss der
Studie.
</p>
<h2>War schon einmal hier</h2>
<p>Wenn Sie schon einmal hier waren, gibt es zwei mögliche Zustände:</p>
<ul>
<li>Sie sind noch eingeloggt</li>
<li>Sie sind nicht mehr eingeloggt</li>
</ul>
<p>
Sofern Sie noch nicht eingeloggt sind, können Sie sich anmelden mit
ihrem gewählten Benutzernamen und dem Passwort. Sie landen dann direkt
auf der Seite, welche ich für meine Studie benötige. Führen Sie dort
die Studie die Studie wie gewohnt durch und beenden Sie diese am
Schluss der Studie mit dem Button "Studie beenden".
</p>
<p>
Wenn Sie bereits eingeloggt sind, dann landen Sie auf der Startseite.
Sie finden in der Mitte einen Button mit der Überschrift "Zur Studie".
Klicken Sie bitte auf diesen Button und führen Sie dann die Studie
durch.
</p>
</div>
<Footer />
</>
);
}

View file

@ -1,15 +0,0 @@
import React from "react";
import "../../App.css";
import Footer from "../../Footer";
export default function Privacy() {
return (
<>
<div className="sitePage">
<h1>Datenschutz</h1>
</div>
"
<Footer />
</>
);
}

View file

@ -0,0 +1,97 @@
import React from "react";
import "../../App.css";
import Footer from "../../Footer";
export default function Privacy() {
return (
<>
<div className="sitePage">
<h1>Datenschutz</h1>
<p>
Nachfolgend werden Sie informiert, welche Daten ich von Ihnen erfasse
und erhebe. Grundsätzlich gilt, dass ich sämtliche Daten nach der
Bachelorthesis wieder lösche. Ausserdem gebe ich keine
personenbezogenen Daten an Dritte weiter. Nachfolgend werden die Daten
in folgende drei Kategorien eingeteilt:
</p>
<ul>
<li>Daten des Webservers</li>
<li>Anmelde- und Umfragedaten</li>
<li>Daten zu biometrischen Verhaltensmerkmalen</li>
</ul>
<h2>Daten des Webservers</h2>
<p>
Diese Webanwendung wird auf einem virtuellen Server bei{" "}
<a href="https://netcup.de">netcup</a> betrieben. Um diese
Webanwendung grundsätzlich bereitzustellen, werden die folgenden Daten
erhoben:{" "}
</p>
<ul>
<li>IP-Adresse der Anfrage</li>
<li>URL der Anfrage</li>
<li>
User-Agent der Anfrage (also z.B. der verwendete Browser usw.)
</li>
<li>Status der Antwort</li>
</ul>
<p>
Diese Informationen werden verwendet, um den reibungslosen Betrieb der
Webseit zu gewährleisten.{" "}
</p>
<h2>Anmelde- und Umfragedaten</h2>
<p>
Im Rahmen der Bachelorthesis erfasse ich einige Merkmale über Sie.
Hierzu zählen einerseits die Logindaten, welche erfasst werden müssen,
damit Sie sich einloggen können. Ausserdem erfasse ich die folgenden
Daten mit einer Umfrage:{" "}
</p>
<ul>
<li>Alter </li>
<li>Geschlecht </li>
<li>Höchster Bildungsstand </li>
<li>Geschätzte Anwenderkenntnisse im Informatikbereich</li>
</ul>
<p>
Die Anmeldedaten werden verwendet, damit Sie sich auf der Webseite
einloggen können. Damit Sie sich nicht jedes Mal anmelden müssen,
verwende ich die Methode von LocalStorage. Im Localstorage wird der
Wert REACT_TOKEN_AUTH_KEY gespeichert, welcher einen Zugangscode
enthält. Die Umfragedaten werden ausgewertet, damit ich die
Teilnehmenden einordnen kann. Die Daten werst sonst nicht
weiterverwertet.
</p>
<h2>Daten zu biometrischen Verhaltensmerkmalen</h2>
<p>
Während der Studie werden biometirsche Daten gesammelt. Zu den
biometrischen Daten gehören Mausbewegungen und Tastaturanschläge.
Diese Daten werden lediglich im Rahmen der Bachelorthesis verwendet
und ausgewertet. Nachdem die Bachelorthesis beendet ist, werden
sämtliche Daten gelöscht. Es erfolgt keine Auswertung der
biometrischen Daten im Zusammenhang mit den Daten der Umfrage.
Allerdings kann der Benutzername, welchen Sie bei der Anmeldung
angegeben haben, verwendet werden.
</p>
<h2>Weitergabe der Daten</h2>
<p>
Grundsätzlich werden die Daten nicht an Dritte weitergegeben. Folgende
Ausnahmen gibt es:
</p>
<ul>
<li>
Der Fernfachhochschule Schweiz werden die Daten falls notwendig
weitergegeben.
</li>
<li>
Sofern es eine gesetzliche Grundlage gibt, werden die Daten auch
weitergegeben.
</li>
<li>
Wie bereits oben erwähnt, läuft die Webanwendung auf einem
virtuellen Server bei <a href="https://netcup.de">netcup</a>. Hierbei gelten die Datenschutzbestimmungen von netcup, welche <a href="https://www.netcup.de/kontakt/datenschutzerklaerung.php">hier</a> eingesehen werden können.
</li>
</ul>
</div>
<Footer />
</>
);
}

View file

@ -0,0 +1,283 @@
import React, { useEffect, useRef, useState } from "react";
import "../../App.css";
import Footer from "../../Footer";
import InputField from "../InputField";
import SubmitField from "../SubmitField";
import ErrorMessage from "../ErrorMessage";
import { Logger } from "@behametrics/logger-web";
import { Button } from "../Button";
import BehaviorStudyInfo from "../BehaviorStudyInfo";
import BehaviorNormal from "../BehaviorNormal";
import BehaviorPhone from "../BehaviorPhone";
import BehaviorStanding from "../BehaviorStanding";
import BehaviorStudyEnd from "../BehaviorStudyEnd";
import { authFetch } from "../../auth/AuthProvider";
import StudyFinished from "../StudyFinished";
export default function Study() {
const _logger = useRef(0);
const [serverUsername, setServerUsername] = useState("");
const [genPassword, setGenPassword] = useState("");
const STATES = {
START: "start",
NORMAL: "normal",
PHONE: "phone",
STANDING: "standing",
END: "end",
};
const [state, setState] = useState(STATES.START);
const [isInputCorrect, setIsInputCorrect] = useState(true);
const errorText =
"Das Passwort und der Benutzername stimmen nicht überein. Bitte prüfen Sie, dass Sie das Passwort richtig abgetippt und den Benutzernamen richtig eingegeben haben.";
useEffect(() => {
_logger.current = new Logger({
inputs: ["keyboard", "wheel", "cursor", "custom"],
});
_logger.current.init();
authFetch("/api/username", {
method: "get",
}).then((response) => {
response.json().then((resp) => {
setServerUsername(resp.username);
});
});
}, []);
let username = "";
const setUsername = (tmp_username) => {
username = tmp_username;
};
let password = "";
const setPassword = (tmp_password) => {
password = tmp_password;
};
const handleLoggerOff = () => {
_logger.current.stop();
console.log("Logger ausgeschaltet");
};
const handleLoggerOn = () => {
_logger.current.start();
console.log("start logging ");
};
const handlePasswordChange = (e) => {
setPassword(e.target.value);
};
const handleUsernameChange = (e) => {
setUsername(e.target.value);
};
const handleOnPasteEvent = (e) => {
e.preventDefault();
return false;
};
const handleOnCopyEvent = (e) => {
e.preventDefault();
return false;
};
const checkIfUsernameIsCorrect = () => {
return serverUsername === username;
};
const receiveRandomPassword = () => {
fetch("/api/rcv_pw", {
method: "get",
}).then((response) => {
response.json().then((resp) => {
setGenPassword(resp.random_password);
});
});
};
const checkIfPasswordIsCorrect = () => {
return genPassword === password;
};
const checkIfValuesAreCorrect = () => {
return checkIfPasswordIsCorrect() && checkIfUsernameIsCorrect();
};
const handleClickAtStepStart = () => {
receiveRandomPassword();
setState(STATES.NORMAL);
handleLoggerOn();
// map username and session with the logs
_logger.current.logCustomEvent({
name: serverUsername,
});
};
const resetInputValues = () => {
let inputElements = document.querySelectorAll(
'div input:not([type="submit"])'
);
for (let i = 0; i < inputElements.length; i++) {
inputElements[i].value = "";
}
};
const handleClickAtStepNormal = () => {
if (checkIfValuesAreCorrect()) {
receiveRandomPassword();
setIsInputCorrect(true);
setState(STATES.PHONE);
} else {
setIsInputCorrect(false);
resetInputValues();
}
};
const handleClickAtStepPhone = () => {
if (checkIfValuesAreCorrect()) {
receiveRandomPassword();
setIsInputCorrect(true);
setState(STATES.STANDING);
} else {
setIsInputCorrect(false);
resetInputValues();
}
};
const handleClickAtStepStanding = () => {
if (checkIfValuesAreCorrect()) {
setIsInputCorrect(true);
setState(STATES.END);
handleLoggerOff();
} else {
setIsInputCorrect(false);
resetInputValues();
}
};
const study_start = (
<>
<BehaviorStudyInfo />
<Button
className="btns"
buttonStyle="btn--primary"
buttonSize="btn--full"
onClick={handleClickAtStepStart}
newTo="study"
>
Studie starten
</Button>
</>
);
const study_normal = (
<>
<BehaviorNormal onCopy={handleOnCopyEvent} genPassword={genPassword} />
{!isInputCorrect && <ErrorMessage message={errorText} />}
<div>
<InputField
LabelName="Benutzername"
onChange={handleUsernameChange}
InputType="text"
InputName="Benutzername"
InputPlaceHolder="Benutzername"
onPaste={handleOnPasteEvent}
/>
<InputField
LabelName="Passwort"
onChange={handlePasswordChange}
InputType="password"
InputName="Passwort"
InputPlaceHolder="Passwort"
onPaste={handleOnPasteEvent}
/>
<SubmitField
LabelName="Weiter zur nächsten Situation"
InputValue="next-situation"
InputName="Weiter"
onClick={handleClickAtStepNormal}
/>
</div>
</>
);
const study_phone = (
<>
<BehaviorPhone genPassword={genPassword} />
{!isInputCorrect && <ErrorMessage message={errorText} />}
<div>
<InputField
LabelName="Benutzername"
onChange={handleUsernameChange}
InputType="text"
InputName="Benutzername"
InputPlaceHolder="Benutzername"
onPaste={handleOnPasteEvent}
/>
<InputField
LabelName="Passwort"
onChange={handlePasswordChange}
InputType="password"
InputName="Passwort"
InputPlaceHolder="Passwort"
onPaste={handleOnPasteEvent}
/>
<SubmitField
LabelName="Weiter zur nächsten Situation"
InputValue="next-situation"
InputName="Weiter"
onClick={handleClickAtStepPhone}
/>
</div>
</>
);
const study_standing = (
<>
<BehaviorStanding genPassword={genPassword} />
{!isInputCorrect && <ErrorMessage message={errorText} />}
<div>
<InputField
LabelName="Benutzername"
onChange={handleUsernameChange}
InputType="text"
InputName="Benutzername"
InputPlaceHolder="Benutzername"
onPaste={handleOnPasteEvent}
/>
<InputField
LabelName="Passwort"
onChange={handlePasswordChange}
InputType="password"
InputName="Passwort"
InputPlaceHolder="Passwort"
onPaste={handleOnPasteEvent}
/>
<SubmitField
LabelName="Studie beenden"
InputValue="stopStudy"
InputName="quit"
onClick={handleClickAtStepStanding}
/>
</div>
</>
);
const study_end = <BehaviorStudyEnd />;
return (
<>
<div className="sitePage">
<h1>Studie</h1>
<StudyFinished />
{state === STATES.START ? study_start : null}
{state === STATES.NORMAL ? study_normal : null}
{state === STATES.PHONE ? study_phone : null}
{state === STATES.STANDING ? study_standing : null}
{state === STATES.END ? study_end : null}
</div>
<Footer />
</>
);
}

View file

@ -9,10 +9,10 @@ export default function Ueber() {
<h1>Über das Projekt</h1> <h1>Über das Projekt</h1>
<p> <p>
Im Rahmen meiner Bachelorthesis an der Fernfachhochschule Schweiz Im Rahmen meiner Bachelorthesis an der Fernfachhochschule Schweiz
möchte ich der Frage nachgehen, wie sich die Verhaltensmerkmale in möchte ich der Frage nachgehen, wie sich die Verhaltensmerkmale (also zum Beispiel Tastaturanschläge und Mausbewegungen) in
unterschiedlichen Situationen unterscheiden. Hierfür habe ich eine unterschiedlichen Situationen unterscheiden. Hierfür habe ich eine
Webanwendung entwickelt, welche die Nutzerinnen und Nutzer möglichst Webanwendung entwickelt, welche die Nutzerinnen und Nutzer möglichst
einfach durch die Studie führt. einfach durch die Studie führt. Damit ich ein paar Personen respektive deren Verhalten erfassen kann, ist es natürlich wichtig, dass mehrere Personen an der Studie teilnehmen. Ausserdem ist es wichtig, dass die teilnehmenden Personen mehrere Male teilnehmen, so dass ich mögliche Unterschiede während des Tagesverlauf bewerten kann.
</p> </p>
<p> <p>
Falls Sie Fragen haben, können Sie diese jederzeit per Mail stellen. Falls Sie Fragen haben, können Sie diese jederzeit per Mail stellen.

View file

@ -51,8 +51,8 @@ export default function Umfrage() {
if (!Number(age)) { if (!Number(age)) {
setAgeErrorMessage("Das Alter muss als Zahl angegeben werden."); setAgeErrorMessage("Das Alter muss als Zahl angegeben werden.");
//setIsSurveyValid(false); setIsSurveyValid(false);
// setIsAgeOk(false); setIsAgeOk(false);
} }
if (gender === "DEFAULT" || gender === "") { if (gender === "DEFAULT" || gender === "") {
setGenderErrorMessage( setGenderErrorMessage(
@ -219,7 +219,7 @@ export default function Umfrage() {
{!isSurveyValidBackend ? ( {!isSurveyValidBackend ? (
<ErrorMessage message={backendErrorMessage} /> <ErrorMessage message={backendErrorMessage} />
) : ( ) : (
<Redirect to="/behavior" /> <Redirect to="/study" />
)} )}
</div> </div>
<Footer /> <Footer />

View file

@ -1,31 +0,0 @@
import React from "react";
import "../../App.css";
import Footer from "../../Footer";
export default function Lizenzen() {
return (
<>
<div className="sitePage">
<h1>Lizenzen und Bildnachweise</h1>
<p>
Nachfolgend sollen die verwendeten Bibliotheken inklusive der Lizenz
aufgeführt werden. Neben den Bibliotheken sollen vorallem auch
Bildnachweise notiert werden.
</p>
<h2>Verwendete Bibliotheken</h2>
<h3>Backend</h3>
<h3>Frontend</h3>
<h2>Bildnachweise</h2>
<ul className="bildnachweise">
<li>
Originalbild für die Startseite:
<a href="https://pixabay.com/illustrations/virtual-identity-digital-identity-69996/">
https://pixabay.com/illustrations/virtual-identity-digital-identity-69996/
</a>
</li>
</ul>
</div>
<Footer />
</>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 KiB

60
requests.sh Executable file
View file

@ -0,0 +1,60 @@
#!/bin/bash
ACTION=$1
VALUE=$2
ACTIONS=(login register rcvpw username data csv prod_data prod_csv)
print_help(){
echo "Usage: $0 ACTION [TOKEN|INPUT_TYPE]"
echo
echo "available actions:"
for el in "${ACTIONS[@]}"; do
echo - "$el"
done
exit 1
}
if [[ -z $1 ]]; then
print_help
fi
case $ACTION in
"${ACTIONS[0]}") # login
echo "login action"
curl localhost:5050/api/login -X POST -d '{"username":"test","password":"test"}'
;;
"${ACTIONS[1]}") # register
echo "register action"
curl localhost:5050/api/register -X POST -d '{"username":"test","password":"test"}'
;;
"${ACTIONS[2]}") # reveice password
echo "rcv_pw action"
curl localhost:5050/api/protected/rcv_pw
;;
"${ACTIONS[3]}") # get current username
echo "get username action"
curl localhost:5050/api/username -X GET -H "Authorization: Bearer $VALUE"
;;
"${ACTIONS[4]}") # get all data from behametricsserver
echo "get data action"
curl localhost:5000/data
;;
"${ACTIONS[5]}") # get all data from behametricsserver
echo "get csv from input action"
curl localhost:5000/data/csv/"${VALUE}"
;;
"${ACTIONS[6]}") # get all data from behametricsserver
echo "get prod data action"
curl behavior.marcocamenzind.ch:5000/data
;;
"${ACTIONS[7]}") # get all data from behametricsserver
echo "get prod csv from input action"
curl behavior.marcocamenzind.ch:5000/data/csv/"${VALUE}"
;;
*)
echo "Error: Action not available"
echo
print_help
;;
esac

View file

@ -1,2 +1,6 @@
podman stop frontend-dev frontend-prod frontend-testing backend-dev backend-prod backend-testing
podman rm frontend-dev frontend-prod frontend-testing backend-dev backend-prod backend-testing
podman rmi app_from_scratch_backend-dev app_from_scratch_frontend-dev
podman rmi caminsha/bt-frontend caminsha/bt-backend
podman-compose down podman-compose down
podman-compose -f docker-compose.prod.yml down podman-compose -f docker-compose.prod.yml down

29
test-prod-containers.yml Normal file
View file

@ -0,0 +1,29 @@
version: '3.7'
services:
frontend-prod:
containername: frontend-testing
build:
context: ./frontend
dockerfile: Dockerfile.prod
ports:
- 3000:80
backend-prod:
container_name: backend-testing
build:
context: ./backend
dockerfile: Dockerfile.prod
environment:
DEBUG: "no"
PORT: 5050
HOST: "0.0.0.0"
behametrics-server:
image: registry.gitlab.com/behametrics/server:latest
container_name: "behametrics-server"
ports:
- 5000:5000
environment:
- MONGO_URI=mongodb://mongodb:27017/behametrics
mongodb:
image: mongo:4.0.1
container_name: "behametrics-mongo"
command: mongod --smallfiles