Change login payload

This commit is contained in:
amcmanu3 2024-02-19 20:18:47 -05:00
parent d168a7f8f0
commit aac35b14d9
3 changed files with 172 additions and 122 deletions

View File

@ -1,7 +1,11 @@
import logging
import binascii
import base64
import urllib
import json
import nh3
from jsonschema import validate
from jsonschema.exceptions import ValidationError
from app.classes.shared.helpers import Helpers
from app.classes.models.users import HelperUsers
@ -47,7 +51,7 @@ class PublicHandler(BaseHandler):
}
if self.request.query:
page_data["query"] = self.request.query
page_data["query"] = self.request.query_arguments.get("next")[0].decode()
# sensible defaults
template = "public/404.html"
@ -77,11 +81,7 @@ class PublicHandler(BaseHandler):
# if we have no page, let's go to login
else:
if self.request.query:
self.redirect("/login?" + self.request.query)
else:
self.redirect("/login")
return
return self.redirect("/login")
self.render(
template,
@ -91,42 +91,74 @@ class PublicHandler(BaseHandler):
)
def post(self, page=None):
# pylint: disable=no-member
error = nh3.clean(self.get_argument("error", "Invalid Login!"))
error_msg = nh3.clean(self.get_argument("error_msg", ""))
# pylint: enable=no-member
login_schema = {
"type": "object",
"properties": {
"username": {
"type": "string",
"pattern": "^[a-z0-9_]+$",
},
"password": {"type": "string"},
},
"required": ["username", "password"],
"additionalProperties": False,
}
try:
data = json.loads(self.request.body)
except json.decoder.JSONDecodeError as e:
logger.error(
"Invalid JSON schema for API"
f" login attempt from {self.get_remote_ip()}"
)
return self.finish_json(
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
validate(data, login_schema)
except ValidationError as e:
logger.error(
"Invalid JSON schema for API"
f" login attempt from {self.get_remote_ip()}"
)
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
page_data = {
"version": self.helper.get_version_string(),
"error": error,
"lang": self.helper.get_setting("language"),
"lang_page": self.helper.get_lang_page(self.helper.get_setting("language")),
"query": "",
}
if self.request.query:
page_data["query"] = self.request.query
page_data["query"] = self.request.query_arguments.get("next")[0].decode()
if page == "login":
data = json.loads(self.request.body)
auth_log.info(
f"User attempting to authenticate from {self.get_remote_ip()}"
)
next_page = "/login"
if self.request.query:
next_page = "/login?" + self.request.query
entered_username = nh3.clean(
self.get_argument("username")
) # pylint: disable=no-member
entered_username = nh3.clean(data["username"]) # pylint: disable=no-member
try:
entered_password = base64.b64decode(
self.get_argument("encPassword")
).decode("utf-8")
except binascii.Error:
error_msg = (
"Hello? Hello? Anybody home?"
" Go straight to jail. Do not pass go."
entered_password = urllib.parse.unquote(
base64.b64decode(data["password"]).decode("utf-8")
)
except binascii.Error:
return self.finish_json(
403,
{
"status": "error",
"error": "Hello? Hello? Anybody home?"
" Go straight to jail. Do not pass go.",
},
)
return self.redirect(f"/login?error_msg={error_msg}")
try:
user_id = HelperUsers.get_user_id_by_name(entered_username.lower())
@ -138,18 +170,18 @@ class PublicHandler(BaseHandler):
f" Authentication failed from remote IP {self.get_remote_ip()}"
" Users does not exist."
)
error_msg = "Incorrect username or password. Please try again."
self.finish_json(
403,
{
"status": "error",
"error": self.helper.translation.translate(
"login", "incorrect", self.helper.get_setting("language")
),
},
)
# self.clear_cookie("user")
# self.clear_cookie("user_data")
self.clear_cookie("token")
if self.request.query:
self.redirect(
f"/login?err or_msg={error_msg}" f"&{self.request.query}"
)
else:
self.redirect(f"/login?error_msg={error_msg}")
return
return self.clear_cookie("token")
# if we don't have a user
if not user_data:
auth_log.error(
@ -158,15 +190,18 @@ class PublicHandler(BaseHandler):
" User does not exist."
)
self.controller.log_attempt(self.get_remote_ip(), entered_username)
error_msg = "Incorrect username or password. Please try again."
self.finish_json(
403,
{
"status": "error",
"error": self.helper.translation.translate(
"login", "incorrect", self.helper.get_setting("language")
),
},
)
# self.clear_cookie("user")
# self.clear_cookie("user_data")
self.clear_cookie("token")
if self.request.query:
self.redirect(f"/login?error_msg={error_msg}&{self.request.query}")
else:
self.redirect(f"/login?error_msg={error_msg}")
return
return self.clear_cookie("token")
# if they are disabled
if not user_data.enabled:
@ -176,18 +211,18 @@ class PublicHandler(BaseHandler):
" User account disabled"
)
self.controller.log_attempt(self.get_remote_ip(), entered_username)
error_msg = (
"User account disabled. Please contact "
"your system administrator for more info."
self.finish_json(
403,
{
"status": "error",
"error": self.helper.translation.translate(
"login", "disabled", self.helper.get_setting("language")
),
},
)
# self.clear_cookie("user")
# self.clear_cookie("user_data")
self.clear_cookie("token")
if self.request.query:
self.redirect(f"/login?error_msg={error_msg}&{self.request.query}")
else:
self.redirect(f"/login?error_msg={error_msg}")
return
return self.clear_cookie("token")
login_result = self.helper.verify_pass(entered_password, user_data.password)
# Valid Login
@ -212,12 +247,9 @@ class PublicHandler(BaseHandler):
user_data.user_id, "Logged in", 0, self.get_remote_ip()
)
if self.request.query_arguments.get("next"):
next_page = self.request.query_arguments.get("next")[0].decode()
else:
next_page = "/panel/dashboard"
self.redirect(next_page)
return self.finish_json(
200, {"status": "ok", "data": {"message": "login successful!"}}
)
else:
auth_log.error(
f"User attempted to log into {entered_username}."
@ -239,12 +271,9 @@ class PublicHandler(BaseHandler):
self.controller.management.add_to_audit_log(
user_data.user_id, "Tried to log in", 0, self.get_remote_ip()
)
if self.request.query:
self.redirect(f"/login?error_msg={error_msg}&{self.request.query}")
else:
self.redirect(f"/login?error_msg={error_msg}")
return self.finish_json(
403,
{"status": "error", "error": error_msg},
)
else:
if self.request.query:
self.redirect("/login?" + self.request.query)
else:
self.redirect("/login")
self.redirect("/login?")

View File

@ -77,55 +77,49 @@
box-shadow: 0 12px 16px 0 hsla(0, 0%, 0%, 0.4);
}
</style>
{% if data['query'] %}
<form id="login" action="/login?{{ data['query'] }}" method="post" onsubmit="encodePass()">
{% else %}
<form id="login" action="/login" method="post" onsubmit="encodePass()">
{% end %}
{% raw xsrf_form_html() %}
<div class="form-group">
<label class="label">{{ translate('login', 'username', data['lang']) }}</label>
<div class="input-group">
<input type="text" class="form-control login-text-input login-input"
placeholder="{{ translate('login', 'username', data['lang']) }}" name="username" id="username"
required="true">
</div>
<form id="login-form" data-query="{{ data.get('query', None) }}">
{% raw xsrf_form_html() %}
<div class="form-group">
<label class="label">{{ translate('login', 'username', data['lang']) }}</label>
<div class="input-group">
<input type="text" class="form-control login-text-input login-input"
placeholder="{{ translate('login', 'username', data['lang']) }}" name="username" id="username"
required="true">
</div>
<div class="form-group">
<label class="label">{{ translate('login', 'password', data['lang']) }}</label>
<div class="input-group">
<input type="password" class="form-control login-text-input login-input"
placeholder="{{ translate('login', 'password', data['lang']) }}" name="password" id="password"
required="true">
</div>
</div>
<div class="form-group">
<label class="label">{{ translate('login', 'password', data['lang']) }}</label>
<div class="input-group">
<input type="password" class="form-control login-text-input login-input"
placeholder="{{ translate('login', 'password', data['lang']) }}" name="password" id="password"
required="true">
</div>
<div class="form-group">
<button class="login-input btn btn-primary submit-btn btn-block">{{ translate('login', 'login',
data['lang']) }}</button>
</div>
{% if error_msg is not None %}
<fieldset style="color: red; text-align: center;">
<span>{{error_msg}}</span>
</fieldset>
{% end %}
<div class="form-group d-flex justify-content-between">
<div class="form-check form-check-flat mt-0">
&nbsp;
</div>
<button onclick="resetPass()" id="#resetPass" form="" class="btn btn-outline-primary btn-sm forgot-password ">{{ translate('login', 'forgotPassword',
data['lang']) }}</button>
</div>
<div class="form-group">
<button class="login-input btn btn-primary submit-btn btn-block">{{ translate('login', 'login',
data['lang']) }}</button>
</div>
<fieldset id="error-field" style="color: red; text-align: center;">
</fieldset>
<div class="form-group d-flex justify-content-between">
<div class="form-check form-check-flat mt-0">
&nbsp;
</div>
<button onclick="resetPass()" id="#resetPass" form=""
class="btn btn-outline-primary btn-sm forgot-password ">{{ translate('login', 'forgotPassword',
data['lang']) }}</button>
</div>
<div class="text-block text-center my-3">
<span class="text-small font-weight-semibold"><a href="https://craftycontrol.com/">Crafty Control
{{data['version'] }}</a> </span>
</div>
<div class="text-block text-center my-3">
<a href="/status" class="text-small forgot-password">{{ translate('login', 'viewStatus',
data['lang']) }}</a>
</div>
</form>
<div class="text-block text-center my-3">
<span class="text-small font-weight-semibold"><a href="https://craftycontrol.com/">Crafty Control
{{data['version'] }}</a> </span>
</div>
<div class="text-block text-center my-3">
<a href="/status" class="text-small forgot-password">{{ translate('login', 'viewStatus',
data['lang']) }}</a>
</div>
</form>
</div>
@ -155,13 +149,13 @@
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
//Register Service worker for mobile app
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', {scope: '/'})
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', { scope: '/' })
.then(function (registration) {
console.log('Service Worker Registered');
});
}
});
async function resetPass(){
async function resetPass() {
let res = await fetch(`/api/v2/crafty/resetPass/`, {
method: 'GET',
});
@ -170,9 +164,38 @@
bootbox.alert(responseData.data)
}
function encodePass(){
$("#encPassword").val(btoa($("#password").val()))
}
$("#login-form").on("submit", async function (e) {
e.preventDefault();
let loginForm = document.getElementById("login-form");
let formData = new FormData(loginForm);
//Create an object from the form data entries
let formDataObject = Object.fromEntries(formData.entries());
console.log(formDataObject)
let res = await fetch(`/login`, {
method: 'POST',
headers: {
'X-XSRFToken': formDataObject._xsrf,
"Content-Type": "application/json"
},
body: JSON.stringify({
"username": formDataObject.username,
"password": btoa(encodeURIComponent(formDataObject.password))
}),
});
let responseData = await res.json();
if (responseData.status === "ok") {
console.log("OK")
if ($("#login-form").data("query")) {
location.href = `${$("#login-form").data("query")}`;
} else {
location.href = `/panel/dashboard`
}
} else {
$("#error-field").html(responseData.error);
}
});
</script>
<style>
.modal-content {
@ -181,9 +204,6 @@
text-align: center;
}
</style>
<input form="login" type="password" class="form-control login-text-input login-input"
placeholder="{{ translate('login', 'password', data['lang']) }}" name="encPassword" id="encPassword"
style="visibility: hidden;">
</body>
</html>

View File

@ -221,7 +221,8 @@
"username": "Username",
"viewStatus": "View Public Status Page",
"incorrect": "Incorrect username or password",
"defaultPath": "The password you entered is the default credential path, not the password. Please find the default password in that location."
"defaultPath": "The password you entered is the default credential path, not the password. Please find the default password in that location.",
"disabled": "User account disabled. Please contact your system administrator for more info."
},
"notify": {
"activityLog": "Activity Logs",
@ -670,4 +671,4 @@
"webhook_body": "Webhook Body",
"webhooks": "Webhooks"
}
}
}