Compare commits

..

No commits in common. "main" and "213dcc91975798582f329952a4b9e8e80ccf2657" have entirely different histories.

46 changed files with 2375 additions and 826 deletions

View file

@ -4,9 +4,6 @@ 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,8 +6,6 @@ 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,4 +1,3 @@
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
@ -17,13 +16,11 @@ 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

@ -113,20 +113,12 @@ 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>"
""" """
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():
@ -141,10 +133,11 @@ 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']) @app.route('/api/protected/rcv_pw', methods=['GET'])
# @flask_praetorian.auth_required
def get_password(): def get_password():
pw = get_random_password() pw = get_random_password()
ret = {'random_password': pw} ret = {'password': pw}
return ret, 200 return ret, 200

View file

@ -23,15 +23,6 @@ def get_random_password():
] ]
second_part = [ second_part = [
"%",
"(",
")",
"$",
"+",
"!",
]
third_part = [
"frisst", "frisst",
"küsst", "küsst",
"begrüsst", "begrüsst",
@ -42,76 +33,28 @@ def get_random_password():
"vergisst", "vergisst",
] ]
third_part = [
"den Vogel",
"die Mücke",
"den Adler",
"den Apfel",
"die Birne",
"die Biene",
"eine Gurke",
]
forth_part = [ forth_part = [
"1 Vogel!", "auf der Terasse.",
"2 Vögel!", "auf der Wiese.",
"3 Vögel!", "im Garten.",
"4 Vögel!", "in der Kühltruhe.",
"5 Vögel!", "auf dem Balkon.",
"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 = ""
password += str(first_part[get_random_value(len(first_part)-1)]) password += str(first_part[get_random_value(len(first_part)-1)])
password += " " + str(second_part[get_random_value(len(second_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(third_part[get_random_value(len(third_part)-1)])
password += " " + str(forth_part[get_random_value(len(forth_part)-1)]) # password += " " + str(forth_part[get_random_value(len(forth_part)-1)])
return password return password

View file

@ -8,8 +8,6 @@ services:
backend-prod: backend-prod:
image: caminsha/bt-backend image: caminsha/bt-backend
container_name: backend-prod container_name: backend-prod
volumes:
- "./database.db:/app/database.db:z"
environment: environment:
DEBUG: "no" DEBUG: "no"
PORT: 5050 PORT: 5050
@ -22,6 +20,6 @@ services:
environment: environment:
- MONGO_URI=mongodb://mongodb:27017/behametrics - MONGO_URI=mongodb://mongodb:27017/behametrics
mongodb: mongodb:
image: mongo:4.0.25 image: mongo:4.0.1
container_name: "behametrics-mongo" container_name: "behametrics-mongo"
command: mongod --smallfiles command: mongod --smallfiles

View file

@ -35,6 +35,6 @@ services:
environment: environment:
- MONGO_URI=mongodb://mongodb:27017/behametrics - MONGO_URI=mongodb://mongodb:27017/behametrics
mongodb: mongodb:
image: mongo:4.0.25 image: mongo:4.0.1
container_name: "behametrics-mongo" container_name: "behametrics-mongo"
command: mongod --smallfiles command: mongod --smallfiles

File diff suppressed because it is too large Load diff

View file

@ -5,11 +5,18 @@
"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",

View file

@ -31,10 +31,7 @@
<title>BA - Marco Camenzind</title> <title>BA - Marco Camenzind</title>
</head> </head>
<body> <body>
<noscript <noscript>Diese Anwendung funktioniert leider nur mit JavaScript. Bitte aktivieren JavaScript in den Einstellungen</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,10 +40,6 @@
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);
} }
@ -55,32 +51,21 @@ a:hover:not(.navbar-logo) {
} }
h1 { h1 {
font-size: 4.5em; font-size: 5em;
margin: 0.7em auto; margin: 0.7em auto;
text-align: center;
} }
.sitePage h2 { .sitePage h2 {
font-size: 3.7em; font-size: 3.75em;
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%;
@ -95,15 +80,4 @@ h1 {
.generated-password { .generated-password {
font-weight: bold; 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,15 +4,15 @@ 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 Study from "./components/pages/Study"; import Study from "./components/pages/Study";
import Secret from "./components/pages/Secret";
function App() { function App() {
return ( return (

View file

@ -92,6 +92,45 @@
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;
@ -109,4 +148,7 @@
flex-direction: column; flex-direction: column;
} }
.social-media-wrap {
flex-direction: column;
}
} }

View file

@ -1,6 +1,7 @@
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

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

View file

@ -1,8 +1,8 @@
import React from "react"; import React from "react";
import "../App.css"; import "../App.css";
import GeneratedPassword from "./GeneratedPassword"; import GeneratedPassword from "./GeneratedPassword"
export default function BehaviorNormal(props) { export default function BehaviorNormal() {
return ( return (
<> <>
<p> <p>
@ -10,7 +10,7 @@ export default function BehaviorNormal(props) {
Passwort eingeben. Verhalten Sie sich einfach so, als ob Sie sich Passwort eingeben. Verhalten Sie sich einfach so, als ob Sie sich
normalerweise anmelden. normalerweise anmelden.
</p> </p>
<GeneratedPassword genPassword={props.genPassword} /> <GeneratedPassword />
</> </>
); );
} }

View file

@ -1,17 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -14,6 +14,7 @@ export default function BehaviorStudyInfo() {
Bitte klicken Sie auf weiter, um mit der Studie zu beginnen. Bitte lesen Bitte klicken Sie auf weiter, um mit der Studie zu beginnen. Bitte lesen
Sie die jeweilige Aufgabe jeweils genau. Sie die jeweilige Aufgabe jeweils genau.
</p> </p>
</> </>
); );
} }

View file

@ -31,12 +31,6 @@
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", "btn--full"]; const SIZES = ["btn--medium", "btn--large"];
export const Button = ({ export const Button = ({
children, children,
type, type,

View file

@ -0,0 +1,29 @@
import React, { useEffect, useState } from "react";
import "../App.css";
export default function GeneratedPassword() {
const [genPassword, setGenPassword] = useState("");
const handleOnCopyEvent = (e) => {
e.preventDefault();
return false;
};
useEffect(() => {
fetch("/api/protected/rcv_pw", {
method: "get",
}).then((response) => {
response.json().then((resp) => {
setGenPassword(resp.password);
});
});
}, []);
return (
<>
<p onCopy={handleOnCopyEvent}>
Das Passwort für diese Situation lautet:{" "}
<span className="generated-password">{genPassword}</span>
</p>
</>
);
}

View file

@ -1,13 +0,0 @@
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,8 +2,8 @@ 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";
export default function HeroSection() { export default function HeroSection() {
const [isLoggedIn] = useAuth(); const [isLoggedIn] = useAuth();
@ -11,7 +11,6 @@ export default function HeroSection() {
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

View file

@ -44,17 +44,6 @@ 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

@ -1,11 +0,0 @@
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,95 +0,0 @@
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

@ -0,0 +1,14 @@
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

@ -1,58 +0,0 @@
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

@ -0,0 +1,15 @@
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

@ -1,97 +0,0 @@
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,123 @@
import React, { useEffect } from "react";
import "../../App.css";
import Footer from "../../Footer";
import InputField from "../InputField";
import SubmitField from "../SubmitField";
import { Logger } from "@behametrics/logger-web";
import BehaviorStudyInfo from "../BehaviorStudyInfo";
import BehaviorNormal from "../BehaviorNormal";
export default function Study() {
let username = "";
const setUsername = (tmp_username) => {
username = tmp_username;
};
let password = "";
const setPassword = (tmp_password) => {
password = tmp_password;
};
let logger = new Logger({
//inputs: ["cursor", "wheel", "keyboard", "touch"],
inputs: ["keyboard"],
// apiUrl: "https://behavior.marcocamenzind.ch",
apiUrl: "http://localhost:5000",
logToConsole: true,
});
logger.init();
const handleLoggerOff = () => {
logger.stop();
console.log("Logger ausgeschaltet");
};
const handleLoggerOn = () => {
logger.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 onSubmitClick = (e) => {
e.preventDefault();
let opts = {
username: username,
password: password,
};
fetch("/api/protected/behavior", {
method: "post",
body: JSON.stringify(opts),
}).then((response) => {
console.log(response.status);
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 :-)");
});
}
});
};
return (
<>
<div className="sitePage">
<h1>Studie</h1>
<button onClick={handleLoggerOn}>LOGGER StaRTEN</button>
<BehaviorStudyInfo />{" "}
<form id="behaviorNormal" action="#">
<SubmitField
LabelName="Starten mit der Studie"
InputValue="next-situation"
InputName="Weiter"
onClick={handleLoggerOn}
/>
</form>{" "}
<BehaviorNormal />
<form id="behaviorNormal" action="#">
<InputField
LabelName="Benutzername"
onChange={handleUsernameChange}
InputType="text"
InputName="Benutzername"
InputPlaceHolder="Benutzername"
onPaste={handleOnPasteEvent}
/>
<InputField
LabelName="Passwort"
onChange={handlePasswordChange}
InputType="password"
InputName="Passwort"
InputPlaceHolder="Benutzername"
onPaste={handleOnPasteEvent}
/>
<SubmitField
LabelNa
me="Weiter zur nächsten Situation"
InputValue="next-situation"
InputName="Weiter"
onClick={onSubmitClick}
/>
</form>
<button onClick={handleLoggerOff}>STOP THAT FUCKING LOGGER</button>
</div>
<Footer />
</>
);
}

View file

@ -1,283 +0,0 @@
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 (also zum Beispiel Tastaturanschläge und Mausbewegungen) in möchte ich der Frage nachgehen, wie sich die Verhaltensmerkmale 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. 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. einfach durch die Studie führt.
</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(

View file

@ -0,0 +1,31 @@
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 />
</>
);
}

View file

@ -1,60 +0,0 @@
#!/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