added web and fix some problems
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Make (push) Successful in 9s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-CMake (push) Successful in 14s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Meson (push) Failing after 8s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Make (push) Successful in 9s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-CMake (push) Successful in 14s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Meson (push) Failing after 8s
This commit is contained in:
1 parent
ccfc8b535e
commit
155c259ea9
29 files changed
+946
-119
No files matched your search
@@ -8,3 +8,5 @@ auth_service
|
||||
users.db
|
||||
*.swp
|
||||
*.log
|
||||
.proxy.sh
|
||||
.no-proxy.sh
|
||||
+61
-14
@@ -6,26 +6,72 @@ void change_password(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
cJSON *jsonbody = cJSON_Parse(hm->body.buf);
|
||||
cJSON *old_password = cJSON_GetObjectItem(jsonbody, "old_password");
|
||||
cJSON *new_password = cJSON_GetObjectItem(jsonbody, "new_password");
|
||||
if (old_password == nullptr || new_password == nullptr) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
cJSON *userid = cJSON_GetObjectItem(jsonbody, "userid");
|
||||
if ((old_password == nullptr || new_password == nullptr) &&
|
||||
userid == nullptr) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"),
|
||||
MG_ESC("must have <old_password>, <new_password>"));
|
||||
return;
|
||||
}
|
||||
cJSON *payload = jwt_get_payload(requestdata->token);
|
||||
char *username = cJSON_GetObjectItem(payload, "username")->valuestring;
|
||||
User *old_user_data = db_get_user_by_username(username);
|
||||
char *password = old_user_data->password;
|
||||
|
||||
if (strcmp(password, old_password->valuestring)) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid old password"));
|
||||
if (!userid) {
|
||||
char *username = cJSON_GetObjectItem(payload, "username")->valuestring;
|
||||
User *old_user_data = db_get_user_by_username(username);
|
||||
if (!old_user_data) {
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"),
|
||||
MG_ESC("failed to update user can't get old_user_data"));
|
||||
cJSON_Delete(payload);
|
||||
}
|
||||
char *password = old_user_data->password;
|
||||
|
||||
if (strcmp(password, old_password->valuestring)) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("invalid old password"));
|
||||
return;
|
||||
}
|
||||
const bool old_is_superuser = old_user_data->is_superuser;
|
||||
User *new_user_data = db_update_user(
|
||||
old_user_data->id, old_user_data->username, old_user_data->email,
|
||||
new_password->valuestring, old_user_data->group, &old_is_superuser);
|
||||
if (!new_user_data) {
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("failed to update user can't update database"));
|
||||
free_user(old_user_data);
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
char responsedata[64] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": true}");
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
free_user(old_user_data);
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
bool is_superuser = cJSON_GetObjectItem(payload, "is_superuser")->valueint;
|
||||
if (!is_superuser) {
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("user is not superuser"));
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
User *old_user_data = db_get_user_by_id(userid->valueint);
|
||||
if (!old_user_data) {
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"),
|
||||
MG_ESC("failed to update user can't get old_user_data"));
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
const bool old_is_superuser = old_user_data->is_superuser;
|
||||
@@ -33,16 +79,17 @@ void change_password(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
old_user_data->id, old_user_data->username, old_user_data->email,
|
||||
new_password->valuestring, old_user_data->group, &old_is_superuser);
|
||||
if (!new_user_data) {
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("failed to update user"));
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("failed to update user can't create new_user_data from root"));
|
||||
free_user(old_user_data);
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
char responsedata[64] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": true}");
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
// free(username);
|
||||
free_user(old_user_data);
|
||||
free_user(new_user_data);
|
||||
cJSON_Delete(payload);
|
||||
}
|
||||
+56
-17
@@ -6,8 +6,8 @@ void change_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
request_with_token *requestdata = check_body(hm);
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
if (!valid) {
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("invalid token"));
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
cJSON *jsonbody = cJSON_Parse(hm->body.buf);
|
||||
@@ -15,21 +15,28 @@ void change_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
cJSON *email = cJSON_GetObjectItem(jsonbody, "email");
|
||||
cJSON *group = cJSON_GetObjectItem(jsonbody, "group");
|
||||
cJSON *is_superuser = cJSON_GetObjectItem(jsonbody, "is_superuser");
|
||||
User *old_user_data = db_get_user_by_username(username->valuestring);
|
||||
cJSON *userid = cJSON_GetObjectItem(jsonbody, "userid");
|
||||
User *old_user_data = nullptr;
|
||||
if (!userid) {
|
||||
old_user_data = db_get_user_by_username(username->valuestring);
|
||||
} else {
|
||||
old_user_data = db_get_user_by_id(userid->valueint);
|
||||
}
|
||||
if (!old_user_data) {
|
||||
mg_http_reply(c, 404, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("user not found"));
|
||||
mg_http_reply(c, 404, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("user not found"));
|
||||
return;
|
||||
}
|
||||
char *password = old_user_data->password;
|
||||
if (!password) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("password is required"));
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("password is required"));
|
||||
return;
|
||||
}
|
||||
if (username == nullptr || email == nullptr ||
|
||||
is_superuser == nullptr || group == nullptr) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
if (username == nullptr || email == nullptr || is_superuser == nullptr ||
|
||||
group == nullptr) {
|
||||
mg_http_reply(c, 400, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"),
|
||||
MG_ESC("must have <username>, <email>, <group, "
|
||||
"optional>, <is_superuser, optional>"));
|
||||
free_user(old_user_data);
|
||||
@@ -39,16 +46,49 @@ void change_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
cJSON *payload = jwt_get_payload(requestdata->token);
|
||||
int id = cJSON_GetObjectItem(payload, "id")->valueint;
|
||||
const bool user_is_superuser = is_superuser->valueint ? true : false;
|
||||
User *updated_user_data = db_update_user(
|
||||
id, username->valuestring, email->valuestring, password,
|
||||
group->valuestring, &user_is_superuser);
|
||||
if (!userid) {
|
||||
User *updated_user_data =
|
||||
db_update_user(id, username->valuestring, email->valuestring, password,
|
||||
group->valuestring, &user_is_superuser);
|
||||
|
||||
if (!updated_user_data) {
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("failed to update user change user request"));
|
||||
cJSON_Delete(payload);
|
||||
free_user(old_user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata),
|
||||
"{\"username\":\"%s\",\"email\":\"%s\",\"group\":\"%s\",\"is_"
|
||||
"superuser\":%s}",
|
||||
username->valuestring, email->valuestring, group->valuestring,
|
||||
is_superuser->valueint ? "true" : "false");
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
free_user(updated_user_data);
|
||||
free_user(old_user_data);
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
bool req_is_superuser =
|
||||
cJSON_GetObjectItem(payload, "is_superuser")->valueint;
|
||||
if (!req_is_superuser) {
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("user is not superuser"));
|
||||
cJSON_Delete(payload);
|
||||
free_user(old_user_data);
|
||||
return;
|
||||
}
|
||||
User *updated_user_data = db_update_user(
|
||||
userid->valueint, username->valuestring, email->valuestring, password,
|
||||
group->valuestring, &user_is_superuser);
|
||||
if (!updated_user_data) {
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("error"),
|
||||
MG_ESC("failed to update user"));
|
||||
mg_http_reply(c, 500, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("failed to update user can't change userdata"));
|
||||
cJSON_Delete(payload);
|
||||
free_user(old_user_data);
|
||||
free(password);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,5 +103,4 @@ void change_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
free_user(updated_user_data);
|
||||
free_user(old_user_data);
|
||||
cJSON_Delete(payload);
|
||||
//free(password);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "user.h"
|
||||
#include "database.h"
|
||||
#include "sql.h"
|
||||
|
||||
User *db_get_user_by_id(const int id) {
|
||||
User *user = nullptr;
|
||||
pthread_mutex_lock(&db_mutex);
|
||||
if (!db) {
|
||||
fprintf(stderr, "Database not initialized\n");
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return nullptr;
|
||||
}
|
||||
sqlite3_stmt *stmt;
|
||||
int rc =
|
||||
sqlite3_prepare_v2(db, SELECT_USER_BY_ID_SQL, -1, &stmt, nullptr);
|
||||
if (rc != SQLITE_OK) {
|
||||
fprintf(stderr, "Cannot prepare statement: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sqlite3_bind_int(stmt, 1, id);
|
||||
|
||||
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
int id = sqlite3_column_int(stmt, 0);
|
||||
const unsigned char *db_username = sqlite3_column_text(stmt, 1);
|
||||
const unsigned char *db_email = sqlite3_column_text(stmt, 2);
|
||||
const unsigned char *db_password = sqlite3_column_text(stmt, 3);
|
||||
const unsigned char *db_group = sqlite3_column_text(stmt, 4);
|
||||
int db_is_superuser = sqlite3_column_int(stmt, 5);
|
||||
user = new_user(id, (char *) db_username, (char *) db_password,
|
||||
(char *) db_email, (char *) db_group, db_is_superuser);
|
||||
}
|
||||
|
||||
if (rc != SQLITE_DONE) {
|
||||
fprintf(stderr, "Error reading data: %s\n", sqlite3_errmsg(db));
|
||||
free_user(user);
|
||||
sqlite3_finalize(stmt);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&db_mutex);
|
||||
return user;
|
||||
}
|
||||
+20
-2
@@ -12,7 +12,6 @@ void delete_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
if (requestdata->error != NULL) {
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC(requestdata->error));
|
||||
// free_request_with_token(requestdata);
|
||||
return;
|
||||
}
|
||||
const bool valid = jwt_verifyJWT(requestdata->token, JWT_DEFAULT_SECRET);
|
||||
@@ -24,7 +23,26 @@ void delete_user(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
}
|
||||
cJSON *payload = jwt_get_payload(requestdata->token);
|
||||
int id = cJSON_GetObjectItem(payload, "id")->valueint;
|
||||
bool user_deleted = db_delete_user(id);
|
||||
cJSON *useridfromjson = cJSON_GetObjectItem(requestdata->body, "userid");
|
||||
cJSON_Print(useridfromjson);
|
||||
if (useridfromjson == NULL) {
|
||||
bool user_deleted = db_delete_user(id);
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": %s}",
|
||||
user_deleted ? "true" : "false");
|
||||
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", responsedata);
|
||||
free_request_with_token(requestdata);
|
||||
cJSON_Delete(payload);
|
||||
return;
|
||||
}
|
||||
bool is_superuser = cJSON_GetObjectItem(payload, "is_superuser")->valueint;
|
||||
if (!is_superuser) {
|
||||
mg_http_reply(c, 403, "Content-Type: application/json\r\n", "{%m:%m}",
|
||||
MG_ESC("error"), MG_ESC("user is not superuser"));
|
||||
return;
|
||||
}
|
||||
bool user_deleted = db_delete_user(useridfromjson->valueint);
|
||||
char responsedata[2048] = {0};
|
||||
snprintf(responsedata, sizeof(responsedata), "{\"success\": %s}",
|
||||
user_deleted ? "true" : "false");
|
||||
|
||||
+78
-11
@@ -4739,7 +4739,7 @@ static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
|
||||
}
|
||||
|
||||
static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
||||
struct pkt *pkt) {
|
||||
struct pkt *pkt, uint16_t mss) {
|
||||
struct mg_connection *c = mg_alloc_conn(lsn->mgr);
|
||||
struct connstate *s;
|
||||
if (c == NULL) {
|
||||
@@ -4747,7 +4747,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
|
||||
return NULL;
|
||||
}
|
||||
s = (struct connstate *) (c + 1);
|
||||
s->dmss = 536; // assume default, RFC-9293 3.7.1
|
||||
s->dmss = mss; // from options in client SYN
|
||||
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
|
||||
memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
|
||||
settmout(c, MIP_TTYPE_KEEPALIVE);
|
||||
@@ -4851,7 +4851,7 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
|
||||
if (pkt->tcp->flags & TH_FIN) {
|
||||
uint8_t flags = TH_ACK;
|
||||
if (mg_ntohl(pkt->tcp->seq) != s->ack) {
|
||||
MG_VERBOSE(("ignoring FIN, SEQ != ACK: %x %x", mg_ntohl(pkt->tcp->seq), s->ack));
|
||||
MG_VERBOSE(("ignoring FIN, %x != %x", mg_ntohl(pkt->tcp->seq), s->ack));
|
||||
tx_tcp(c->mgr->ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
|
||||
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
|
||||
return;
|
||||
@@ -4934,6 +4934,57 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TCP backlog
|
||||
struct mg_backlog {
|
||||
uint16_t port, mss; // use port=0 for available entries
|
||||
uint8_t age;
|
||||
};
|
||||
|
||||
static int backlog_insert(struct mg_connection *c, uint16_t port,
|
||||
uint16_t mss) {
|
||||
struct mg_backlog *p = (struct mg_backlog *) c->data;
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(c->data) / sizeof(*p); i++) {
|
||||
if (p[i].port != 0) continue;
|
||||
p[i].age = 2; // remove after two calls, average 1.5 call rate
|
||||
p[i].port = port, p[i].mss = mss;
|
||||
return (int) i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct mg_backlog *backlog_retrieve(struct mg_connection *c,
|
||||
uint16_t key, uint16_t port) {
|
||||
struct mg_backlog *p = (struct mg_backlog *) c->data;
|
||||
if (key >= sizeof(c->data) / sizeof(*p)) return NULL;
|
||||
if (p[key].port != port) return NULL;
|
||||
p += key;
|
||||
return p;
|
||||
}
|
||||
|
||||
static void backlog_remove(struct mg_connection *c, uint16_t key) {
|
||||
struct mg_backlog *p = (struct mg_backlog *) c->data;
|
||||
p[key].port = 0;
|
||||
}
|
||||
|
||||
static void backlog_maintain(struct mg_connection *c) {
|
||||
struct mg_backlog *p = (struct mg_backlog *) c->data;
|
||||
size_t i; // dec age and remove those where it reaches 0
|
||||
for (i = 0; i < sizeof(c->data) / sizeof(*p); i++) {
|
||||
if (p[i].port == 0) continue;
|
||||
if (p[i].age != 0) --p[i].age;
|
||||
if (p[i].age == 0) p[i].port = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void backlog_poll(struct mg_mgr *mgr) {
|
||||
struct mg_connection *c = NULL;
|
||||
for (c = mgr->conns; c != NULL; c = c->next) {
|
||||
if (!c->is_udp && c->is_listening) backlog_maintain(c);
|
||||
}
|
||||
}
|
||||
|
||||
// process options (MSS)
|
||||
static void handle_opt(struct connstate *s, struct tcp *tcp) {
|
||||
uint8_t *opts = (uint8_t *) (tcp + 1);
|
||||
@@ -4991,15 +5042,30 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
|
||||
if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
|
||||
// ignore RST if not connected
|
||||
} else if (pkt->tcp->flags & TH_SYN) {
|
||||
// TODO(): handle_opt(s, pkt->tcp); // process options (MSS)
|
||||
// At this point, s = NULL, there is no connection.
|
||||
// Use peer's source port as ISN, in order to recognise the handshake
|
||||
uint32_t isn = mg_htonl((uint32_t) mg_ntohs(pkt->tcp->sport));
|
||||
tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
|
||||
struct connstate cs; // At this point, s = NULL, there is no connection
|
||||
int key;
|
||||
uint32_t isn;
|
||||
if (pkt->tcp->sport != 0) {
|
||||
handle_opt(&cs, pkt->tcp); // process options (MSS)
|
||||
key = backlog_insert(c, pkt->tcp->sport, cs.dmss); // backlog options (MSS)
|
||||
if (key < 0) return; // no room in backlog, discard SYN, client retries
|
||||
// Use peer's src port and bl key as ISN, to later identify the handshake
|
||||
isn = (mg_htonl(((uint32_t)key << 16) | mg_ntohs(pkt->tcp->sport)));
|
||||
tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
|
||||
} // what should we do when port=0 ? Linux takes port 0 as any other port
|
||||
} else if (pkt->tcp->flags & TH_FIN) {
|
||||
tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||
} else if (mg_htonl(pkt->tcp->ack) == mg_htons(pkt->tcp->sport) + 1U) {
|
||||
accept_conn(c, pkt);
|
||||
} else if ((uint16_t) (mg_htonl(pkt->tcp->ack) - 1) ==
|
||||
mg_htons(pkt->tcp->sport)) {
|
||||
uint16_t key = (uint16_t) ((mg_htonl(pkt->tcp->ack) - 1) >> 16);
|
||||
struct mg_backlog *b = backlog_retrieve(c, key, pkt->tcp->sport);
|
||||
if (b != NULL) {
|
||||
accept_conn(c, pkt, b->mss); // pass options
|
||||
backlog_remove(c, key);
|
||||
} else if (!c->is_accepted) { // not an actual match, reset
|
||||
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||
// TODO(scaprile): revisit this and below, weird scenarios
|
||||
}
|
||||
} else if (!c->is_accepted) { // no peer
|
||||
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||
} else {
|
||||
@@ -5127,6 +5193,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
|
||||
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
|
||||
ifp->ndrop, ifp->nerr));
|
||||
#endif
|
||||
backlog_poll(ifp->mgr);
|
||||
}
|
||||
// Handle gw ARP request timeout, order is important
|
||||
if (expired_1000ms && ifp->state == MG_TCPIP_STATE_IP) {
|
||||
@@ -5460,7 +5527,7 @@ static void setdns4(struct mg_tcpip_if *ifp, uint32_t *ip) {
|
||||
MG_DEBUG(("Set DNS URL to %s", dnsc->url));
|
||||
if (ifp->mgr->use_dns6) return;
|
||||
if (dnsc->c != NULL) mg_close_conn(dnsc->c);
|
||||
if (!mg_dnsc_init(ifp->mgr, dnsc)) // create DNS connection
|
||||
if (!mg_dnsc_init(ifp->mgr, dnsc)) // create DNS connection
|
||||
MG_ERROR(("DNS connection creation failed"));
|
||||
}
|
||||
|
||||
|
||||
+36
-36
@@ -20,7 +20,7 @@
|
||||
#ifndef MONGOOSE_H
|
||||
#define MONGOOSE_H
|
||||
|
||||
#define MG_VERSION "7.18"
|
||||
#define MG_VERSION "7.19"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -3693,6 +3693,41 @@ struct mg_tcpip_driver_tms570_data {
|
||||
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
|
||||
|
||||
struct mg_tcpip_driver_xmc7_data {
|
||||
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
|
||||
uint8_t phy_addr;
|
||||
};
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 3
|
||||
#endif
|
||||
|
||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||
do { \
|
||||
static struct mg_tcpip_driver_xmc7_data driver_data_; \
|
||||
static struct mg_tcpip_if mif_; \
|
||||
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
|
||||
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
|
||||
mif_.ip = MG_TCPIP_IP; \
|
||||
mif_.mask = MG_TCPIP_MASK; \
|
||||
mif_.gw = MG_TCPIP_GW; \
|
||||
mif_.driver = &mg_tcpip_driver_xmc7; \
|
||||
mif_.driver_data = &driver_data_; \
|
||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||
mg_tcpip_init(mgr, &mif_); \
|
||||
MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC
|
||||
|
||||
struct mg_tcpip_driver_xmc_data {
|
||||
@@ -3739,41 +3774,6 @@ struct mg_tcpip_driver_xmc_data {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7
|
||||
|
||||
struct mg_tcpip_driver_xmc7_data {
|
||||
int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5
|
||||
uint8_t phy_addr;
|
||||
};
|
||||
|
||||
#ifndef MG_TCPIP_PHY_ADDR
|
||||
#define MG_TCPIP_PHY_ADDR 0
|
||||
#endif
|
||||
|
||||
#ifndef MG_DRIVER_MDC_CR
|
||||
#define MG_DRIVER_MDC_CR 3
|
||||
#endif
|
||||
|
||||
#define MG_TCPIP_DRIVER_INIT(mgr) \
|
||||
do { \
|
||||
static struct mg_tcpip_driver_xmc7_data driver_data_; \
|
||||
static struct mg_tcpip_if mif_; \
|
||||
driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \
|
||||
driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \
|
||||
mif_.ip = MG_TCPIP_IP; \
|
||||
mif_.mask = MG_TCPIP_MASK; \
|
||||
mif_.gw = MG_TCPIP_GW; \
|
||||
mif_.driver = &mg_tcpip_driver_xmc7; \
|
||||
mif_.driver_data = &driver_data_; \
|
||||
MG_SET_MAC_ADDRESS(mif_.mac); \
|
||||
mg_tcpip_init(mgr, &mif_); \
|
||||
MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ static void root_handler(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
}
|
||||
|
||||
static const struct route routes[] = {
|
||||
{"GET", "/", root_handler},
|
||||
{"GET", "/#", root_handler},
|
||||
{"POST", "/api/token", get_token},
|
||||
{"POST", "/api/token/verify", verify_token},
|
||||
{"POST", "/api/users", get_all_users},
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define SELECT_ALL_USERS_SQL "select * from users"
|
||||
#define SELECT_USER_BY_USERNAME_SQL "select * from users where username = ?"
|
||||
#define SELECT_USER_BY_ID_SQL "select * from users where id = ?"
|
||||
#define INSERT_USER_USERNAME_EMAIL_PASSWORD_SQL \
|
||||
"insert into users (username, email, password) values (?, ?, ?)"
|
||||
#define INSERT_USER_USERNAME_EMAIL_PASSWORD_GROUP_SQL \
|
||||
|
||||
@@ -62,3 +62,4 @@ User *db_update_user(const int userid, const char *username, const char *email,
|
||||
const char *password, const char *group,
|
||||
const bool *is_superuser);
|
||||
bool db_delete_user(const int id);
|
||||
User *db_get_user_by_id(const int id);
|
||||
+1
-1
@@ -14,5 +14,5 @@ void verify_token(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
MG_ESC("invalid token"));
|
||||
return;
|
||||
}
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{%m:%m}", MG_ESC("valid"), MG_ESC("true"));
|
||||
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{%m:true}", MG_ESC("valid"));
|
||||
}
|
||||
@@ -18,7 +18,7 @@ printf "==> ${BLUE}Testing${CYAN} POST${BWHITE} /api/token${RESET} "
|
||||
curl \
|
||||
--silent \
|
||||
-X POST \
|
||||
-d '{"username":"tola","password":"2808"}' \
|
||||
-d '{"username":"tola","password":"e0c7bfa5b8e4ae0cecfc1f14093a71e05c27abd93a3850fc35f008c3baf866b4"}' \
|
||||
localhost:8222/api/token &> api_token_test.log
|
||||
sleep 0.1
|
||||
res=$(cat api_token_test.log)
|
||||
@@ -107,7 +107,7 @@ curl \
|
||||
localhost:8222/api/token/verify &> api_token_verify_test.log
|
||||
sleep 0.1
|
||||
res=$(cat api_token_verify_test.log)
|
||||
if [[ "$res" == *'{"valid":"true"}'* ]]; then
|
||||
if [[ "$res" == *'{"valid":true}'* ]]; then
|
||||
printf "[$GREEN OK $RESET]\n"
|
||||
success=$(($success+1))
|
||||
else
|
||||
@@ -424,7 +424,7 @@ reqtoken=$(cat api_token_test.log | sed -e "s/{//g" | sed -e "s/}//g")
|
||||
curl \
|
||||
--silent \
|
||||
-X POST \
|
||||
-d "{\"old_password\":\"2808\",\"new_password\":\"1234\",$reqtoken}" \
|
||||
-d "{\"old_password\":\"e0c7bfa5b8e4ae0cecfc1f14093a71e05c27abd93a3850fc35f008c3baf866b4\",\"new_password\":\"1234\",$reqtoken}" \
|
||||
localhost:8222/api/users/password &> api_users_password_test.log
|
||||
sleep 0.1
|
||||
res=$(cat api_users_password_test.log)
|
||||
|
||||
+2
-2
@@ -2,14 +2,14 @@
|
||||
{
|
||||
"username": "tola",
|
||||
"email": "mail@example.com",
|
||||
"password": "2808",
|
||||
"password": "e0c7bfa5b8e4ae0cecfc1f14093a71e05c27abd93a3850fc35f008c3baf866b4",
|
||||
"group": "root",
|
||||
"is_superuser": true
|
||||
},
|
||||
{
|
||||
"username": "lisa",
|
||||
"email": "lisa@example.com",
|
||||
"password": "asdf",
|
||||
"password": "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b",
|
||||
"group": "users",
|
||||
"is_superuser": false
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
@charset "UTF-8";/*!
|
||||
* Bootstrap v5.3.5 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/:root,[data-bs-theme=light]{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-black:#000;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-primary-text-emphasis:#052c65;--bs-secondary-text-emphasis:#2b2f32;--bs-success-text-emphasis:#0a3622;--bs-info-text-emphasis:#055160;--bs-warning-text-emphasis:#664d03;--bs-danger-text-emphasis:#58151c;--bs-light-text-emphasis:#495057;--bs-dark-text-emphasis:#495057;--bs-primary-bg-subtle:#cfe2ff;--bs-secondary-bg-subtle:#e2e3e5;--bs-success-bg-subtle:#d1e7dd;--bs-info-bg-subtle:#cff4fc;--bs-warning-bg-subtle:#fff3cd;--bs-danger-bg-subtle:#f8d7da;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#9ec5fe;--bs-secondary-border-subtle:#c4c8cb;--bs-success-border-subtle:#a3cfbb;--bs-info-border-subtle:#9eeaf9;--bs-warning-border-subtle:#ffe69c;--bs-danger-border-subtle:#f1aeb5;--bs-light-border-subtle:#e9ecef;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-color-rgb:33,37,41;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(33, 37, 41, 0.75);--bs-secondary-color-rgb:33,37,41;--bs-secondary-bg:#e9ecef;--bs-secondary-bg-rgb:233,236,239;--bs-tertiary-color:rgba(33, 37, 41, 0.5);--bs-tertiary-color-rgb:33,37,41;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:inherit;--bs-link-color:#0d6efd;--bs-link-color-rgb:13,110,253;--bs-link-decoration:underline;--bs-link-hover-color:#0a58ca;--bs-link-hover-color-rgb:10,88,202;--bs-code-color:#d63384;--bs-highlight-color:#212529;--bs-highlight-bg:#fff3cd;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#dee2e6;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(13, 110, 253, 0.25);--bs-form-valid-color:#198754;--bs-form-valid-border-color:#198754;--bs-form-invalid-color:#dc3545;--bs-form-invalid-border-color:#dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#dee2e6;--bs-body-color-rgb:222,226,230;--bs-body-bg:#212529;--bs-body-bg-rgb:33,37,41;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(222, 226, 230, 0.75);--bs-secondary-color-rgb:222,226,230;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(222, 226, 230, 0.5);--bs-tertiary-color-rgb:222,226,230;--bs-tertiary-bg:#2b3035;--bs-tertiary-bg-rgb:43,48,53;--bs-primary-text-emphasis:#6ea8fe;--bs-secondary-text-emphasis:#a7acb1;--bs-success-text-emphasis:#75b798;--bs-info-text-emphasis:#6edff6;--bs-warning-text-emphasis:#ffda6a;--bs-danger-text-emphasis:#ea868f;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#dee2e6;--bs-primary-bg-subtle:#031633;--bs-secondary-bg-subtle:#161719;--bs-success-bg-subtle:#051b11;--bs-info-bg-subtle:#032830;--bs-warning-bg-subtle:#332701;--bs-danger-bg-subtle:#2c0b0e;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#084298;--bs-secondary-border-subtle:#41464b;--bs-success-border-subtle:#0f5132;--bs-info-border-subtle:#087990;--bs-warning-border-subtle:#997404;--bs-danger-border-subtle:#842029;--bs-light-border-subtle:#495057;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherLine truncated
|
||||
/*# sourceMappingURL=bootstrap.min.css.map */
|
||||
@@ -0,0 +1,73 @@
|
||||
.form {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
transition: 0.3s;
|
||||
background-color: black;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.form.confirmform {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.form.active {
|
||||
height: 100%;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.formbody {
|
||||
padding: 10px;
|
||||
background-color: gray;
|
||||
backdrop-filter: blur(5px);
|
||||
border-radius: 10px;
|
||||
/* box-shadow: -5px -5px 30px 30px gray; */
|
||||
}
|
||||
|
||||
.loginformheader {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loginforminputbody {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.loginforminput {
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.loginforminputbodyflex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.loginforminputbodyflex>button {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.loginformbutton {
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
background-color: rgb(59, 59, 197);
|
||||
color: white;
|
||||
transition: 0.3s;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.loginformbutton:hover {
|
||||
background-color: rgb(151, 151, 241);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
.message {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
border-radius: 10px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.messagetextbox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.messagetext {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.message.active.error {
|
||||
pointer-events: all;
|
||||
height: 10%;
|
||||
background-color: rgb(233, 70, 70);
|
||||
}
|
||||
|
||||
.message.active.success {
|
||||
pointer-events: all;
|
||||
height: 10%;
|
||||
background-color: rgb(76, 209, 76);
|
||||
}
|
||||
+152
-32
@@ -1,35 +1,155 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>auth_service</title>
|
||||
</head>
|
||||
<style>
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 200px;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<h1>it's work</h1>
|
||||
<div
|
||||
class="login-form"
|
||||
style="display: flex; flex-direction: column; max-width: 200px"
|
||||
>
|
||||
<h2>Login</h2>
|
||||
<label for="username_input">Username</label>
|
||||
<input type="text" id="username_input" />
|
||||
<label for="password_input">Password</label>
|
||||
<input type="password" id="password_input" />
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/css/loginform.css">
|
||||
<link rel="stylesheet" href="/css/message.css">
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<title>admin</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar navbar-expand-lg bg-body-tertiary gap-3 p-2">
|
||||
<button class="btn btn-danger" id="exitbutton">Exit</button>
|
||||
<button class="btn btn-warning" id="adduserbutton">Adduser</button>
|
||||
<h1 class="usernameheader"></h1>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="themecheckbox" class="form-check-input">
|
||||
<label for="themecheckbox" class="form-check-label">Dark theme</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form loginform" id="loginform">
|
||||
<form class="formbody loginformbody" id="loginformbody">
|
||||
<h1 class="loginformheader">Login</h1>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="loginforminputusername" class="form-control" placeholder="John">
|
||||
<label for="loginforminputusername">Username</label>
|
||||
</div>
|
||||
<script>
|
||||
console.log("hello world");
|
||||
const username_input = document.querySelector("#username_input");
|
||||
const password_input = document.querySelector("#password_input");
|
||||
console.log(username_input, password_input);
|
||||
</script>
|
||||
</body>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" required id="loginforminputpassword" class="form-control" placeholder="***">
|
||||
<label for="loginforminputpassword">Password</label>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary">login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form adduserform">
|
||||
<form class="formbody adduserformbody">
|
||||
<h1 class="loginformheader">Add User</h1>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="adduserformusername" class="form-control">
|
||||
<label for="adduserformusername">Username</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="adduserformemail" class="form-control">
|
||||
<label for="adduserformemail">Email</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" required id="adduserformpassword" class="form-control">
|
||||
<label for="adduserformpassword">Password</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="adduserformgroup" class="form-control">
|
||||
<label for="adduserformgroup">Group</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="adduserformissuperuser" class="form-check-input">
|
||||
<label for="adduserformissuperuser" class="form-check-label">Is Superuser</label>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary">Add</button>
|
||||
<button id="canceladduser" class="btn btn-primary">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form changeuserform">
|
||||
<form class="formbody changeuserformbody">
|
||||
<h1 class="loginformheader">Change User Data</h1>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="changeuserformusername" class="form-control" placeholder="Username">
|
||||
<label for="changeuserformusername">Username</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" id="changeuserformemail" class="form-control" placeholder="***">
|
||||
<label for="changeuserformemail">email</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="changeuserformgroup" class="form-control">
|
||||
<label for="changeuserformgroup">Group</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="changeuserformissuperuser" class="form-check-input">
|
||||
<label for="changeuserformissuperuser" class="form-check-label">Is Superuser</label>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary">Change</button>
|
||||
<button id="cancelchangeuser" class="btn btn-primary">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form confirmform">
|
||||
<div class="formbody confirmformbody">
|
||||
<h1>Are you sure?</h1>
|
||||
<div class="d-grid gap-2">
|
||||
<button id="yes" class="btn btn-primary">Confirm</button>
|
||||
<button id="no" class="btn btn-primary">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form changepasswordform">
|
||||
<form class="formbody changepasswordformbody">
|
||||
<h1 class="loginformheader">Change Password</h1>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" required id="changepasswordnewpassword" class="form-control" placeholder="***">
|
||||
<label for="changepasswordnewpassword">New password</label>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary">Change</button>
|
||||
<button class="btn btn-primary" id="cancelchangepassword">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="message">
|
||||
<div class="messagetextbox">
|
||||
<h3 class="messagetext"></h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table">
|
||||
<table class="table">
|
||||
<thead class="alluserstablehead">
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>username</th>
|
||||
<th>email</th>
|
||||
<th>group</th>
|
||||
<th>is_superuser</th>
|
||||
<th>delete</th>
|
||||
<th>change password</th>
|
||||
<th>change user data</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="alluserstablebody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script src="/js/security.js"></script>
|
||||
<script src="/js/message.js"></script>
|
||||
<script src="/js/routes.js"></script>
|
||||
<script src="/js/window.js"></script>
|
||||
<script src="/js/theme.js"></script>
|
||||
<script src="/js/login.js"></script>
|
||||
<script src="/js/get_all_users.js"></script>
|
||||
<script src="/js/add_user.js"></script>
|
||||
<script src="/js/del_user.js"></script>
|
||||
<script src="/js/change_password.js"></script>
|
||||
<script src="/js/change_user.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
const adduserbutton = document.querySelector('#adduserbutton')
|
||||
const adduserform = document.querySelector('.adduserform')
|
||||
const canceladduserbutton = document.querySelector('#canceladduser')
|
||||
const adduserformbody = document.querySelector('.adduserformbody')
|
||||
const usernameinput = document.querySelector('#adduserformusername')
|
||||
const passwordinput = document.querySelector('#adduserformpassword')
|
||||
const groupinput = document.querySelector('#adduserformgroup')
|
||||
const is_superuserinput = document.querySelector('#adduserformissuperuser')
|
||||
const emailinput = document.querySelector('#adduserformemail')
|
||||
|
||||
adduserbutton.addEventListener('click', () => {
|
||||
adduserform.classList.add('active')
|
||||
})
|
||||
|
||||
canceladduserbutton.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
adduserform.classList.remove('active')
|
||||
})
|
||||
|
||||
adduserformbody.addEventListener('submit', async (e) => {
|
||||
e.preventDefault()
|
||||
const hashedpassword = await hashPassword(passwordinput.value)
|
||||
const new_user = {
|
||||
username: usernameinput.value,
|
||||
email: emailinput.value,
|
||||
password: hashedpassword,
|
||||
group: groupinput.value,
|
||||
is_superuser: is_superuserinput.checked
|
||||
}
|
||||
const status = await fetch(routes.adduser(), {
|
||||
method: 'POST',
|
||||
body: `{"token":"${localStorage.getItem('token')}","username":"${new_user.username}","email":"${new_user.email}","password":"${new_user.password}","group":"${new_user.group}","is_superuser":"${new_user.is_superuser}"}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
if (!status.error) {
|
||||
adduserform.classList.remove('active')
|
||||
await get_all_users()
|
||||
notification("Пользователь успешно добавлен", "success")
|
||||
usernameinput.value = ""
|
||||
passwordinput.value = ""
|
||||
groupinput.value = ""
|
||||
} else {
|
||||
notification(status.error, "error")
|
||||
}
|
||||
})
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Bootstrap v5.3.5 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e(t.Popper)}(this,(function(t){"use strict";function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const i in t)if("default"!==i){const s=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,s.get?s:{enumerable:!0,get:()=>t[i]})}return e.default=t,Object.freeze(e)}const i=e(t),s=new Map,n={set(t,e,i){s.has(t)||s.set(t,new Map);const n=s.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>s.has(t)&&s.get(t).get(e)||null,remove(t,e){if(!s.has(t))return;const i=s.get(t);i.delete(e),0===i.size&&s.delete(t)}},o="transitionend",r=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),a=t=>{t.dispatchEvent(new Event(o))},l=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),c=t=>l(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(r(t)):null,h=t=>{if(!l(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},d=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),u=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?u(t.parentNode):null},_=()=>{},g=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,m=[],p=()=>"rtl"===document.documentElement.dir,b=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,s=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=s,t.jQueryInterface)}},"loading"===document.readyState?(m.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of m)t()})),m.push(e)):e()},v=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,y=(t,e,i=!0)=>{if(!i)return void v(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const s=Number.parseFloat(e),n=Number.parseFloat(i);return s||n?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let n=!1;const r=({target:i})=>{i===e&&(n=!0,e.removeEventListener(o,r),v(t))};e.addEventListener(o,r),setTimeout((()=>{n||a(e)}),s)},w=(t,e,i,s)=>{const n=t.length;let o=t.indexOf(e);return-1===o?!i&&s?t[n-1]:t[0]:(o+=i?1:-1,s&&(o=(o+n)%n),t[Math.max(0,Math.min(o,n-1))])},A=/[^.]*(?=\..*)\.|.*/,E=/\..*/,C=/::\d+$/,T={};let k=1;const $={mouseenter:"mouseover",mouseleave:"mouseout"},S=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${k++}`||t.uidEvent||k++}function O(t){const e=L(t);return t.uidEvent=e,T[e]=T[e]||{},T[e]}function I(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function D(t,e,i){const s="string"==typeof e,n=s?i:e||i;let o=M(t);return S.has(o)||(o=t),[s,n,o]}function N(t,e,i,s,n){if("string"!=typeof e||!t)return;let[o,r,a]=D(e,i,s);if(e in $){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=O(t),c=l[a]||(l[a]={}),h=I(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&n);const d=L(r,e.replace(A,"")),u=o?function(t,e,i){return function s(n){const o=t.querySelectorAll(e);for(let{target:r}=n;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return F(n,{delegateTarget:r}),s.oneOff&&j.off(t,n.type,e,i),i.apply(r,[n])}}(t,i,r):function(t,e){return function i(s){return F(s,{delegateTarget:t}),i.oneOff&&j.off(t,s.type,e),e.apply(t,[s])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=n,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function P(t,e,i,s,n){const o=I(e[i],s,n);o&&(t.removeEventListener(i,o,Boolean(n)),delete e[i][o.uidEvent])}function x(t,e,i,s){const n=e[i]||{};for(const[o,r]of Object.entries(n))o.includes(Line truncated
|
||||
//# sourceMappingURL=bootstrap.min.js.map
|
||||
@@ -0,0 +1,34 @@
|
||||
const changepasswordform = document.querySelector('.changepasswordform')
|
||||
const cancelchangepassword = document.querySelector('#cancelchangepassword')
|
||||
const changepasswordformbody = document.querySelector('.changepasswordformbody')
|
||||
const changepasswordnewpassword = document.querySelector('#changepasswordnewpassword')
|
||||
|
||||
let changepassuserid = "";
|
||||
|
||||
const change_password = (userid) => {
|
||||
changepasswordform.classList.add('active')
|
||||
changepassuserid = userid
|
||||
}
|
||||
|
||||
cancelchangepassword.addEventListener('click', e => {
|
||||
e.preventDefault()
|
||||
changepasswordform.classList.remove('active')
|
||||
})
|
||||
|
||||
changepasswordformbody.addEventListener('submit', async e => {
|
||||
e.preventDefault()
|
||||
const hashedpassword = await hashPassword(changepasswordnewpassword.value)
|
||||
const status = await fetch(routes.change_password_url(), {
|
||||
method: 'POST',
|
||||
body: `{"token":"${localStorage.getItem('token')}","userid":${changepassuserid},"new_password":"${hashedpassword}"}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
if (!status.error) {
|
||||
notification("Пароль успешно изменен", "success")
|
||||
changepasswordform.classList.remove('active')
|
||||
changepasswordnewpassword.value = ""
|
||||
} else {
|
||||
notification(status.error, "error")
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
const changeuserform = document.querySelector('.changeuserform')
|
||||
const changeuserformbody = document.querySelector('.changeuserformbody')
|
||||
const changeuserformusername = document.querySelector('#changeuserformusername')
|
||||
const changeuserformemail = document.querySelector('#changeuserformemail')
|
||||
const changeuserformgroup = document.querySelector('#changeuserformgroup')
|
||||
const changeuserformissuperuser = document.querySelector('#changeuserformissuperuser')
|
||||
const cancelchangeuser = document.querySelector("#cancelchangeuser")
|
||||
|
||||
let changedatauserid = "";
|
||||
let userdata = "";
|
||||
|
||||
const change_user_data = async (userid) => {
|
||||
changeuserform.classList.add('active')
|
||||
changedatauserid = userid
|
||||
const all_users = await fetch(routes.all_users(), {
|
||||
method: 'POST',
|
||||
body: `{"token":"${localStorage.getItem('token')}"}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
userdata = all_users.find(usr => usr.id === userid)
|
||||
changeuserformusername.value = userdata.username
|
||||
changeuserformgroup.value = userdata.group
|
||||
changeuserformissuperuser.checked = userdata.is_superuser === "1"
|
||||
changeuserformemail.value = userdata.email
|
||||
}
|
||||
|
||||
cancelchangeuser.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
changeuserform.classList.remove('active')
|
||||
})
|
||||
|
||||
changeuserformbody.addEventListener('submit', async (e) => {
|
||||
e.preventDefault()
|
||||
let request = {
|
||||
token: localStorage.getItem('token'),
|
||||
userid: changedatauserid,
|
||||
username: changeuserformusername.value,
|
||||
email: changeuserformemail.value,
|
||||
is_superuser: changeuserformissuperuser.checked,
|
||||
group: changeuserformgroup.value
|
||||
};
|
||||
const status = await fetch(routes.change_user(), {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(request)
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
if (!status.error) {
|
||||
notification("Данные пользователя успешно изменены", "success")
|
||||
changeuserform.classList.remove('active')
|
||||
await get_all_users()
|
||||
} else {
|
||||
notification(status.error, "error")
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,41 @@
|
||||
const userstablebody = document.querySelector('#alluserstablebody')
|
||||
const confirmform = document.querySelector('.confirmform')
|
||||
const confirmformcancel = document.querySelector('#no')
|
||||
const confirmformok = document.querySelector('#yes')
|
||||
|
||||
let useridtodelete = "";
|
||||
|
||||
userstablebody.addEventListener('click', e => {
|
||||
if (e.target.classList.contains('deleteuser')) {
|
||||
useridtodelete = e.target.id
|
||||
confirmform.classList.add("active")
|
||||
}
|
||||
if (e.target.classList.contains('changepassword')) {
|
||||
change_password(e.target.id)
|
||||
}
|
||||
if (e.target.classList.contains('changeuser')) {
|
||||
change_user_data(parseInt(e.target.id))
|
||||
}
|
||||
})
|
||||
|
||||
confirmformcancel.addEventListener('click', () => {
|
||||
useridtodelete = ""
|
||||
confirmform.classList.remove('active')
|
||||
})
|
||||
|
||||
confirmformok.addEventListener('click', async () => {
|
||||
const status = await fetch(routes.deluser(), {
|
||||
method: 'DELETE',
|
||||
body: `{"token":"${localStorage.getItem('token')}","userid":${useridtodelete}}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
if (status.success) {
|
||||
confirmform.classList.remove('active')
|
||||
await get_all_users()
|
||||
notification("Пользователь успешно удален", "success")
|
||||
} else {
|
||||
notification("Can't delete user", "error")
|
||||
confirmform.classList.remove('active')
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
const get_all_users = async () => {
|
||||
const response = await fetch(routes.all_users(), {
|
||||
method: "POST",
|
||||
body: `{"token":"${localStorage.getItem("token")}"}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
const alluserstablebody = document.querySelector('#alluserstablebody')
|
||||
alluserstablebody.innerHTML = ""
|
||||
for (const user of response) {
|
||||
alluserstablebody.innerHTML += `
|
||||
<tr>
|
||||
<th><p>${user.id}</p></th>
|
||||
<th>${user.username}</th>
|
||||
<th>${user.email}</th>
|
||||
<th>${user.group}</th>
|
||||
<th>${user.is_superuser}</th>
|
||||
<th><button class="deleteuser btn btn-danger" id="${user.id}">Delete</button></th>
|
||||
<th><button class="changepassword btn btn-warning" id="${user.id}">Change password</button></th>
|
||||
<th><button class="changeuser btn btn-warning" id="${user.id}">Change user data</button></th>
|
||||
</tr>
|
||||
`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
const loginform = document.querySelector('#loginform')
|
||||
const loginformbody = document.querySelector('#loginformbody')
|
||||
const loginforminputusername = document.querySelector('#loginforminputusername')
|
||||
const loginforminputpassword = document.querySelector('#loginforminputpassword')
|
||||
const exitbutton = document.querySelector('#exitbutton')
|
||||
const usernameheader = document.querySelector('.usernameheader')
|
||||
|
||||
if (localStorage.getItem("token") === null) {
|
||||
loginform.classList.add("active")
|
||||
}
|
||||
|
||||
loginformbody.addEventListener('submit', (e) => {
|
||||
e.preventDefault()
|
||||
hashPassword(loginforminputpassword.value).then(hashedpassword => {
|
||||
login(loginforminputusername.value, hashedpassword)
|
||||
})
|
||||
})
|
||||
|
||||
const login = async (username, password) => {
|
||||
const response = await fetch(routes.login(), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
// 'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
// mode: 'no-cors',
|
||||
body: `{"username":"${username}","password":"${password}"}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
if (error.message === "Unexpected end of JSON input") {
|
||||
notification(`Ошибка на сервере: Создайте файл users.json и запишите в него первого пользователя`, "error")
|
||||
} else {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
}
|
||||
})
|
||||
if (response.error) {
|
||||
loginforminputusername.classList.add('is-invalid')
|
||||
loginforminputpassword.classList.add('is-invalid')
|
||||
notification("Неправильный логин или пароль", "error")
|
||||
}
|
||||
if (response.token) {
|
||||
notification("Успешно", "success")
|
||||
loginform.classList.remove("active")
|
||||
localStorage.setItem("token", response.token)
|
||||
await get_user_data()
|
||||
loginforminputusername.value = ""
|
||||
loginforminputpassword.value = ""
|
||||
loginforminputusername.classList.remove('is-invalid')
|
||||
loginforminputpassword.classList.remove('is-invalid')
|
||||
}
|
||||
}
|
||||
|
||||
const get_user_data = async () => {
|
||||
const response = await fetch(routes.user(), {
|
||||
method: "POST",
|
||||
body: `{"token":"${localStorage.getItem("token")}"}`
|
||||
}).then(data => data.json()).then(jsondata => jsondata).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
if (response.is_superuser) {
|
||||
await get_all_users()
|
||||
usernameheader.innerHTML = response.username
|
||||
} else {
|
||||
document.querySelector('#alluserstablebody').innerHTML = ""
|
||||
loginform.classList.add("active")
|
||||
notification("Вы не можете войти потому что не являетесь администратором", "error")
|
||||
localStorage.clear()
|
||||
}
|
||||
if (response.id) {
|
||||
localStorage.setItem("userdata", JSON.stringify(response))
|
||||
}
|
||||
}
|
||||
|
||||
message.addEventListener('click', () => {
|
||||
message.classList.remove("active")
|
||||
})
|
||||
|
||||
exitbutton.addEventListener('click', () => {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('userdata')
|
||||
loginform.classList.add('active')
|
||||
notification('Вы вышли', "success")
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
const message = document.querySelector('.message')
|
||||
const messagetext = document.querySelector('.messagetext')
|
||||
|
||||
const notification = (text, type) => {
|
||||
if (type === "error") {
|
||||
message.classList.remove('success')
|
||||
message.classList.add('error')
|
||||
} else {
|
||||
message.classList.remove('error')
|
||||
message.classList.add('success')
|
||||
}
|
||||
messagetext.innerHTML = text
|
||||
message.classList.add('active')
|
||||
setTimeout(() => {
|
||||
message.classList.remove('active')
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
const host = window.location.origin
|
||||
const prefix = 'api'
|
||||
|
||||
const routes = {
|
||||
login: () => [host, prefix, 'token'].join('/'),
|
||||
user: () => [host, prefix, 'users', 'user'].join('/'),
|
||||
all_users: () => [host, prefix, 'users'].join('/'),
|
||||
access: () => [host, prefix, 'token', 'verify'].join('/'),
|
||||
adduser: () => [host, prefix, 'users', 'add'].join('/'),
|
||||
deluser: () => [host, prefix, 'users'].join('/'),
|
||||
change_password_url: () => [host, prefix, 'users', 'password'].join('/'),
|
||||
change_user: () => [host, prefix, 'users'].join('/')
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
const hashPassword = async (password) => {
|
||||
const encoder = new TextEncoder()
|
||||
const data = encoder.encode(password)
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
||||
const hashHex = hashArray.map(b=>('00' + b.toString(16)).slice(-2)).join('')
|
||||
return hashHex
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
const themecheckbox = document.querySelector('#themecheckbox')
|
||||
|
||||
themecheckbox.addEventListener('click', (e) => {
|
||||
if (themecheckbox.checked) {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
||||
localStorage.setItem('bs-theme', 'dark')
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'light')
|
||||
localStorage.setItem('bs-theme', 'light')
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,27 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
var theme = localStorage.getItem('bs-theme')
|
||||
if (theme) {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||
if (theme === 'dark') {
|
||||
themecheckbox.checked = true
|
||||
}
|
||||
}
|
||||
if (localStorage.getItem('token')) {
|
||||
fetch(routes.access(), {
|
||||
method: 'POST',
|
||||
body: `{"token": "${localStorage.getItem('token')}"}`
|
||||
}).then(data => data.json()).then(jsondata => {
|
||||
if (jsondata.valid) {
|
||||
document.querySelector('.loginform').classList.remove('active')
|
||||
get_all_users()
|
||||
} else {
|
||||
document.querySelector('.loginform').classList.add('active')
|
||||
}
|
||||
}).catch((error) => {
|
||||
notification(`Ошибка на сервере: ${error}`, "error")
|
||||
})
|
||||
usernameheader.innerHTML = JSON.parse(localStorage.getItem('userdata')).username
|
||||
} else {
|
||||
document.querySelector('.loginform').classList.add('active')
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user