From 4190e4fd1ad37197ff570233e3edfd423b81baf9 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Wed, 25 Dec 2024 18:02:14 +0300 Subject: [PATCH 01/40] =?UTF-8?q?init:=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D1=81=D0=BA=D0=BE=D0=B9=20=D1=87=D0=B0=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 72 +++++++++++++++++++ .../java/ru/project/ClientApplication.java | 14 ++++ 2 files changed, 86 insertions(+) create mode 100644 Client/src/main/java/ru/project/Client.java create mode 100644 Client/src/main/java/ru/project/ClientApplication.java diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java new file mode 100644 index 0000000..2c26a8a --- /dev/null +++ b/Client/src/main/java/ru/project/Client.java @@ -0,0 +1,72 @@ +package ru.project; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.util.Scanner; + +public class Client { + private Socket socket; + private DataOutputStream out; + private DataInputStream in; + private Scanner scanner; + + public Client() throws IOException { + scanner = new Scanner(System.in); + socket = new Socket("localhost", 8189); + out = new DataOutputStream(socket.getOutputStream()); + in = new DataInputStream(socket.getInputStream()); + + new Thread(() -> { + try { + while (true) { + String message = in.readUTF(); + if (message.startsWith("/")) { + if (message.equalsIgnoreCase("/exitok")) { + break; + } + } else { + System.out.println(message); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + disconnect(); + } + }).start(); + + while (true) { + String message = scanner.nextLine(); + out.writeUTF(message); + if (message.equalsIgnoreCase("/exit")) { + break; + } + } + } + + public void disconnect() { + try { + if (in != null) { + in.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (out != null) { + out.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (socket != null) { + socket.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/Client/src/main/java/ru/project/ClientApplication.java b/Client/src/main/java/ru/project/ClientApplication.java new file mode 100644 index 0000000..e4252de --- /dev/null +++ b/Client/src/main/java/ru/project/ClientApplication.java @@ -0,0 +1,14 @@ +package ru.project; + +import java.io.IOException; + + +public class ClientApplication { + public static void main(String[] args) { + try { + new Client(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} From 890f8a2c244ec16ed851099be091b01e63ceca9e Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Wed, 25 Dec 2024 18:31:47 +0300 Subject: [PATCH 02/40] =?UTF-8?q?=D0=9E=D1=82=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BB=D0=B8=D1=87=D0=BD=D1=8B=D1=85=20=D1=81?= =?UTF-8?q?=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 9 +++++++++ Server/src/main/java/ru/project/Server.java | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 6bdca6f..d3efeb9 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -35,6 +35,15 @@ public ClientHandler(Socket socket, Server server) throws IOException { if (message.equalsIgnoreCase("/exit")) { sendMsg("/exitok"); break; + } else if (message.startsWith("/w ")) { + String[] tokens = message.split(" ", 3); + if (tokens.length == 3) { + String recipient = tokens[1]; + String privateMessage = tokens[2]; + server.sendPrivateMessage(this, recipient, privateMessage); + } else { + sendMsg("Неверный формат комманды. Используйте /w <никнейм> <сообщение>"); + } } } else { server.broadcastMessage(username + " : " + message); diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 6fe59bc..78a9c94 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -42,4 +42,14 @@ public void broadcastMessage(String message){ c.sendMsg(message); } } + public void sendPrivateMessage(ClientHandler sender, String recipient, String message) { + for (ClientHandler client : clients) { + if (client.getUsername().equals(recipient)) { + client.sendMsg(sender.getUsername() + ": " + message); + sender.sendMsg(recipient + ": " + message); + return; + } + } + sender.sendMsg("Ошибка: пользователь с ником " + recipient + " не найден."); + } } From 37ffad154fcab7e70e11fa998f2caf2421ced28e Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Wed, 25 Dec 2024 18:36:43 +0300 Subject: [PATCH 03/40] =?UTF-8?q?=D0=9E=D1=82=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BB=D0=B8=D1=87=D0=BD=D1=8B=D1=85=20=D1=81?= =?UTF-8?q?=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 9 +++++++++ Server/src/main/java/ru/project/Server.java | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 6bdca6f..fcad112 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -35,6 +35,15 @@ public ClientHandler(Socket socket, Server server) throws IOException { if (message.equalsIgnoreCase("/exit")) { sendMsg("/exitok"); break; + } else if (message.startsWith("/w ")) { + String[] tokens = message.split(" ", 3); + if (tokens.length == 3) { + String recipient = tokens[1]; + String privateMessage = tokens[2]; + server.sendPrivateMessage(this, recipient, privateMessage); + } else { + sendMsg("Ошибка. Используйте формат /w <никнейм> <сообщение>"); + } } } else { server.broadcastMessage(username + " : " + message); diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 6fe59bc..78a9c94 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -42,4 +42,14 @@ public void broadcastMessage(String message){ c.sendMsg(message); } } + public void sendPrivateMessage(ClientHandler sender, String recipient, String message) { + for (ClientHandler client : clients) { + if (client.getUsername().equals(recipient)) { + client.sendMsg(sender.getUsername() + ": " + message); + sender.sendMsg(recipient + ": " + message); + return; + } + } + sender.sendMsg("Ошибка: пользователь с ником " + recipient + " не найден."); + } } From 1a5a38b1fed54fc06caeebc758afdb7aa140f830 Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Sun, 29 Dec 2024 13:53:02 +0300 Subject: [PATCH 04/40] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 4 ++ .../main/java/ru/project/Authenticator.java | 6 ++ .../main/java/ru/project/ClientHandler.java | 30 ++++++++++ Server/src/main/java/ru/project/Server.java | 17 +++++- .../ru/project/inMemoryAuthenticator.java | 56 +++++++++++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 Server/src/main/java/ru/project/Authenticator.java create mode 100644 Server/src/main/java/ru/project/inMemoryAuthenticator.java diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 2c26a8a..331769e 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -26,6 +26,10 @@ public Client() throws IOException { if (message.equalsIgnoreCase("/exitok")) { break; } + if (message.startsWith("/authOK ")) { + System.out.println("Авторизация прошла успешно! Имя пользователя: " + + message.split(" ")[1]); + } } else { System.out.println(message); } diff --git a/Server/src/main/java/ru/project/Authenticator.java b/Server/src/main/java/ru/project/Authenticator.java new file mode 100644 index 0000000..b5472b4 --- /dev/null +++ b/Server/src/main/java/ru/project/Authenticator.java @@ -0,0 +1,6 @@ +package ru.project; + +public interface Authenticator { + void initialize(); + boolean authenticate(ClientHandler clientHandler, String login, String password); +} diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index d3efeb9..40f8747 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -28,7 +28,33 @@ public ClientHandler(Socket socket, Server server) throws IOException { new Thread(() -> { try { System.out.println("Клиент подключился " + socket.getPort()); + //Цикл логина + while (true) { + sendMsg("Для начала работы надо пройти аутентификацию. Формат команды /log login password"); + String message = in.readUTF(); + if (message.startsWith("/")) { + if (message.equals("/exit")) { + sendMsg("/exitOK"); + break; + } + if (message.equals("/log ")) { + String[] tokens = message.split(" ", 3); + if (tokens.length != 3) { + sendMsg("Ошибка авторизации"); + continue; + } + if (server.getAuthenticator().authenticate(this, tokens[1], tokens[2])) { + break; + } + } + } + else { + sendMsg("Неверная команда"); + continue; + } + } + //Цикл работы while (true) { String message = in.readUTF(); if (message.startsWith("/")) { @@ -93,4 +119,8 @@ public void disconnect() { public String getUsername() { return username; } + + public void setUsername(String username) { + this.username = username; + } } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 78a9c94..b6d97c3 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -9,18 +9,21 @@ public class Server { private int port; private List clients; + private Authenticator authenticator; public Server(int port) { this.port = port; clients = new CopyOnWriteArrayList<>(); + authenticator = new inMemoryAuthenticator(this); } public void start(){ try (ServerSocket serverSocket = new ServerSocket(port)) { System.out.println("Сервер запущен на порту: " + port); + authenticator.initialize(); while (true) { Socket socket = serverSocket.accept(); - subscribe(new ClientHandler(socket, this)); + new ClientHandler(socket, this); } } catch (IOException e) { @@ -52,4 +55,16 @@ public void sendPrivateMessage(ClientHandler sender, String recipient, String me } sender.sendMsg("Ошибка: пользователь с ником " + recipient + " не найден."); } + public boolean isUserLoggedIn(String username){ + for (ClientHandler client : clients) { + if (client.getUsername().equals(username)) { + return true; + } + } + return false; + } + + public Authenticator getAuthenticator() { + return authenticator; + } } diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java new file mode 100644 index 0000000..349d0b4 --- /dev/null +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -0,0 +1,56 @@ +package ru.project; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class inMemoryAuthenticator implements Authenticator { + public class User { + private String username; + private String login; + private String password; + + public User(String username, String login, String password) { + this.username = username; + this.login = login; + this.password = password; + } + } + private List users; + private Server server; + public inMemoryAuthenticator(Server server) { + users = new CopyOnWriteArrayList<>(); + this.server = server; + users.add(new User("admin", "admin", "admin")); + users.add(new User("element1", "element", "123456")); + users.add(new User("yellowFish", "yellowFish", "fishing2")); + } + @Override + public void initialize() { + System.out.println("Инициализация"); + } + private String getUsernameByLoginAndPassword(String login, String password) { + for (User u : users) { + if (u.login.equals(login) && u.password.equals(password)) { + return u.username; + } + } + return null; + } + + @Override + public boolean authenticate(ClientHandler clientHandler, String login, String password) { + String username = getUsernameByLoginAndPassword(login, password); + if (username == null) { + clientHandler.sendMsg("Неверный логин и/или пароль"); + return false; + } + if (server.isUserLoggedIn(username)) { + clientHandler.sendMsg("Данный пользователь уже в сети"); + return false; + } + clientHandler.setUsername(username); + server.subscribe(clientHandler); + clientHandler.sendMsg("/authOK " + username); + return true; + } +} From beb841254ded85cfd8903b9a8cf43ac63e5833a8 Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Sun, 29 Dec 2024 18:47:30 +0300 Subject: [PATCH 05/40] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 40f8747..0fb1497 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -38,8 +38,8 @@ public ClientHandler(Socket socket, Server server) throws IOException { sendMsg("/exitOK"); break; } - if (message.equals("/log ")) { - String[] tokens = message.split(" ", 3); + String[] tokens = message.split(" ", 3); + if (tokens[0].equals("/log")) { if (tokens.length != 3) { sendMsg("Ошибка авторизации"); continue; @@ -51,7 +51,6 @@ public ClientHandler(Socket socket, Server server) throws IOException { } else { sendMsg("Неверная команда"); - continue; } } //Цикл работы From e25a5536a7dd91ea342a77babfd0dae0163948ee Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Mon, 6 Jan 2025 23:08:39 +0300 Subject: [PATCH 06/40] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BD=D0=B0:=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20?= =?UTF-8?q?isLogged=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D1=8F=20=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0=20=D0=B2=20=D1=86=D0=B8=D0=BA=D0=BB=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D1=8B=20=D0=B8=D0=B7=20=D1=86=D0=B8=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=20=D0=B0=D1=83=D1=82=D0=B5=D0=BD=D1=82=D0=B8=D1=84=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 9bb59fd..2a047c9 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -12,6 +12,7 @@ public class ClientHandler { private DataInputStream in; private DataOutputStream out; private String username; + private boolean isLogged = false; public ClientHandler(Socket socket, Server server) throws IOException { this.socket = socket; @@ -40,6 +41,7 @@ public ClientHandler(Socket socket, Server server) throws IOException { } if (server.getAuthenticator() .authenticate(this, tokens[1], tokens[2])) { + isLogged = true; break; } } @@ -49,7 +51,7 @@ public ClientHandler(Socket socket, Server server) throws IOException { } } //Цикл работы - while (true) { + while (isLogged) { String message = in.readUTF(); if (message.startsWith("/")) { if (message.equalsIgnoreCase("/exit")) { From c89754211f85e045a789bb028b67c1b4caeccde9 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Mon, 6 Jan 2025 23:39:13 +0300 Subject: [PATCH 07/40] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B2=20=D1=87=D0=B0=D1=82?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 4 +++ .../main/java/ru/project/Authenticator.java | 1 + .../main/java/ru/project/ClientHandler.java | 15 ++++++-- .../ru/project/inMemoryAuthenticator.java | 36 +++++++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 331769e..84841fc 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -30,6 +30,10 @@ public Client() throws IOException { System.out.println("Авторизация прошла успешно! Имя пользователя: " + message.split(" ")[1]); } + if (message.startsWith("/regOK ")) { + System.out.println("Регистрация прошла успешно! Имя пользователя: " + + message.split(" ")[1]); + } } else { System.out.println(message); } diff --git a/Server/src/main/java/ru/project/Authenticator.java b/Server/src/main/java/ru/project/Authenticator.java index b5472b4..df49723 100644 --- a/Server/src/main/java/ru/project/Authenticator.java +++ b/Server/src/main/java/ru/project/Authenticator.java @@ -3,4 +3,5 @@ public interface Authenticator { void initialize(); boolean authenticate(ClientHandler clientHandler, String login, String password); + boolean registration(ClientHandler clientHandler, String username, String login, String password); } diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 2a047c9..283dcb4 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -25,15 +25,15 @@ public ClientHandler(Socket socket, Server server) throws IOException { System.out.println("Клиент подключился " + socket.getPort()); //Цикл логина while (true) { - sendMsg("Для начала работы надо пройти аутентификацию. Формат команды /log login password"); - + sendMsg("Для начала работы надо пройти аутентификацию. Формат команды /log login password\n" + + "или регистрацию. Формат команды /reg username login password "); String message = in.readUTF(); if (message.startsWith("/")) { if (message.equals("/exit")) { sendMsg("/exitOK"); break; } - String[] tokens = message.split(" ", 3); + String[] tokens = message.split(" "); if (tokens[0].equals("/log")) { if (tokens.length != 3) { sendMsg("Ошибка авторизации"); @@ -45,6 +45,15 @@ public ClientHandler(Socket socket, Server server) throws IOException { break; } } + if (message.startsWith("/reg")) { + if (tokens.length != 4) { + sendMsg("Неверный формат команды /reg"); + continue; + } + if (server.getAuthenticator() + .registration(this, tokens[1], tokens[2], tokens[3])); + break; + } } else { sendMsg("Неверная команда"); diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index 349d0b4..cbb67f8 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -53,4 +53,40 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa clientHandler.sendMsg("/authOK " + username); return true; } + private boolean isLoginAlreadyExist(String login) { + for (User u : users) { + if (u.login.equals(login)) { + return true; + } + } + return false; + } + private boolean isUsernameAlreadyExist(String username) { + for (User u : users) { + if (u.username.equals(username)) { + return true; + } + } + return false; + } + @Override + public boolean registration(ClientHandler clientHandler, String username, String login, String password) { + if (login.length() < 3 || password.length() < 3 || username.length() < 3) { + clientHandler.sendMsg("Логин 3+ символа, пароль 3+ символа, имя пользователя 3+ символа"); + return false; + } + if (isLoginAlreadyExist(login)) { + clientHandler.sendMsg("Такой логин уже используется"); + return false; + } + if (isUsernameAlreadyExist(username)) { + clientHandler.sendMsg("Такое имя пользователя уже используется"); + return false; + } + users.add(new User(username, login, password)); + clientHandler.setUsername(username); + server.subscribe(clientHandler); + clientHandler.sendMsg("/regOK " + username); + return true; + } } From 8273247a14b398d8fb45085f8dc3bd7e209be2c8 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Tue, 7 Jan 2025 00:06:25 +0300 Subject: [PATCH 08/40] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 6 ++++-- Server/src/main/java/ru/project/inMemoryAuthenticator.java | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 283dcb4..a1a3811 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -45,14 +45,16 @@ public ClientHandler(Socket socket, Server server) throws IOException { break; } } - if (message.startsWith("/reg")) { + if (tokens[0].equals("/reg")) { if (tokens.length != 4) { sendMsg("Неверный формат команды /reg"); continue; } if (server.getAuthenticator() - .registration(this, tokens[1], tokens[2], tokens[3])); + .registration(this, tokens[1], tokens[2], tokens[3])) { + isLogged = true; break; + } } } else { diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index cbb67f8..47efc9b 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -21,8 +21,6 @@ public inMemoryAuthenticator(Server server) { users = new CopyOnWriteArrayList<>(); this.server = server; users.add(new User("admin", "admin", "admin")); - users.add(new User("element1", "element", "123456")); - users.add(new User("yellowFish", "yellowFish", "fishing2")); } @Override public void initialize() { From f9b12fb65851ca96c3a61103efbdc5d69c2a3fbe Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Tue, 7 Jan 2025 01:28:19 +0300 Subject: [PATCH 09/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D1=83?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=BA=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/ru/project/ClientHandler.java | 16 ++++++++++++++++ Server/src/main/java/ru/project/Role.java | 6 ++++++ Server/src/main/java/ru/project/Server.java | 16 +++++++++++++++- .../java/ru/project/inMemoryAuthenticator.java | 11 +++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 Server/src/main/java/ru/project/Role.java diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index a1a3811..4c83b59 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -2,8 +2,10 @@ import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.EOFException; import java.io.IOException; import java.net.Socket; +import java.net.SocketException; public class ClientHandler { @@ -13,6 +15,7 @@ public class ClientHandler { private DataOutputStream out; private String username; private boolean isLogged = false; + private Role role; public ClientHandler(Socket socket, Server server) throws IOException { this.socket = socket; @@ -77,6 +80,13 @@ public ClientHandler(Socket socket, Server server) throws IOException { } else { sendMsg("Неверный формат комманды. Используйте /w <никнейм> <сообщение>"); } + } else if (message.startsWith("/kick ")) { + String[] tokens = message.split(" ", 2); + if (tokens.length != 2) { + sendMsg("Неверный формат команды /kick"); + continue; + } + server.kickUser(tokens[1], this); } } else { server.broadcastMessage(username + " : " + message); @@ -130,4 +140,10 @@ public String getUsername() { public void setUsername(String username) { this.username = username; } + public void setRole(Role role) { + this.role = role; + } + public Role getRole() { + return role; + } } diff --git a/Server/src/main/java/ru/project/Role.java b/Server/src/main/java/ru/project/Role.java new file mode 100644 index 0000000..b3efc8a --- /dev/null +++ b/Server/src/main/java/ru/project/Role.java @@ -0,0 +1,6 @@ +package ru.project; + +public enum Role { + USER, + ADMIN; +} diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index b6d97c3..b791441 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -63,8 +64,21 @@ public boolean isUserLoggedIn(String username){ } return false; } - public Authenticator getAuthenticator() { return authenticator; } + public void kickUser(String usernameToKick, ClientHandler adminHandler) { + if (!adminHandler.getRole().equals(Role.ADMIN)) { + adminHandler.sendMsg("Недостаточно прав"); + } + for (ClientHandler client : clients) { + if (client.getUsername().equals(usernameToKick)) { + client.sendMsg("/exit"); + client.disconnect(); + broadcastMessage("Пользователь " + usernameToKick + " был отключён администратором"); + return; + } + } + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToKick + " не найден"); + } } diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index 47efc9b..a796a05 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -47,6 +47,11 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa return false; } clientHandler.setUsername(username); + if (clientHandler.getUsername().equals("admin")) { + clientHandler.setRole(Role.ADMIN); + } else { + clientHandler.setRole(Role.USER); + } server.subscribe(clientHandler); clientHandler.sendMsg("/authOK " + username); return true; @@ -83,8 +88,14 @@ public boolean registration(ClientHandler clientHandler, String username, String } users.add(new User(username, login, password)); clientHandler.setUsername(username); + if (clientHandler.getUsername().equals("admin")) { + clientHandler.setRole(Role.ADMIN); + } else { + clientHandler.setRole(Role.USER); + } server.subscribe(clientHandler); clientHandler.sendMsg("/regOK " + username); return true; } + } From 8c3ae3bfff6290ef2585f73e055b423327ab8507 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Tue, 7 Jan 2025 11:15:25 +0300 Subject: [PATCH 10/40] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D0=B5=20kickUser(String=20usernameToKick,=20Client?= =?UTF-8?q?Handler=20adminHandler)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/Server.java | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index b791441..def0613 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -68,17 +68,18 @@ public Authenticator getAuthenticator() { return authenticator; } public void kickUser(String usernameToKick, ClientHandler adminHandler) { - if (!adminHandler.getRole().equals(Role.ADMIN)) { - adminHandler.sendMsg("Недостаточно прав"); - } - for (ClientHandler client : clients) { - if (client.getUsername().equals(usernameToKick)) { - client.sendMsg("/exit"); - client.disconnect(); - broadcastMessage("Пользователь " + usernameToKick + " был отключён администратором"); - return; + if (adminHandler.getRole().equals(Role.ADMIN)) { + for (ClientHandler client : clients) { + if (client.getUsername().equals(usernameToKick)) { + client.sendMsg("/exit"); + client.disconnect(); + broadcastMessage("Пользователь " + usernameToKick + " был отключён администратором"); + return; + } } + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToKick + " не найден"); + } else { + adminHandler.sendMsg("Недостаточно прав"); } - adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToKick + " не найден"); } } From 1651808f9084cda98322014e23c8343409b2c928 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sat, 11 Jan 2025 11:49:22 +0300 Subject: [PATCH 11/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20IOExcepti?= =?UTF-8?q?on=20=D0=B2=20ClientHandler,=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BD=D0=BE=D0=B5=20=D0=B7=D0=B0=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D1=8B=20=D1=81=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=BC=20=D0=BD=D0=B0=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 7 ++----- Server/src/main/java/ru/project/Server.java | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 4c83b59..ef117d0 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -14,7 +14,6 @@ public class ClientHandler { private DataInputStream in; private DataOutputStream out; private String username; - private boolean isLogged = false; private Role role; public ClientHandler(Socket socket, Server server) throws IOException { @@ -44,7 +43,6 @@ public ClientHandler(Socket socket, Server server) throws IOException { } if (server.getAuthenticator() .authenticate(this, tokens[1], tokens[2])) { - isLogged = true; break; } } @@ -55,7 +53,6 @@ public ClientHandler(Socket socket, Server server) throws IOException { } if (server.getAuthenticator() .registration(this, tokens[1], tokens[2], tokens[3])) { - isLogged = true; break; } } @@ -65,7 +62,7 @@ public ClientHandler(Socket socket, Server server) throws IOException { } } //Цикл работы - while (isLogged) { + while (true) { String message = in.readUTF(); if (message.startsWith("/")) { if (message.equalsIgnoreCase("/exit")) { @@ -93,7 +90,7 @@ public ClientHandler(Socket socket, Server server) throws IOException { } } } catch (IOException e) { - e.printStackTrace(); + System.out.println("Сокет закрыт, клиент на порту " + socket.getPort() + " отключен."); } finally { disconnect(); } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index def0613..8601691 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -71,8 +71,7 @@ public void kickUser(String usernameToKick, ClientHandler adminHandler) { if (adminHandler.getRole().equals(Role.ADMIN)) { for (ClientHandler client : clients) { if (client.getUsername().equals(usernameToKick)) { - client.sendMsg("/exit"); - client.disconnect(); + client.sendMsg("/exitok"); broadcastMessage("Пользователь " + usernameToKick + " был отключён администратором"); return; } From 10b4360ae25d368100e1802da55d747bbe6978b3 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sat, 11 Jan 2025 12:21:28 +0300 Subject: [PATCH 12/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20SocketExc?= =?UTF-8?q?eption=20=D0=B2=20Client.=20=D0=A2=D0=B0=D0=BA=D0=B6=D0=B5=20?= =?UTF-8?q?=D1=86=D0=B8=D0=BA=D0=BB=D1=8B=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B8=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D1=8E=D1=82=20=D0=B4=D0=BE?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D0=B0=20socket.isClosed()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 84841fc..7d6df0d 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -4,6 +4,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; +import java.net.SocketException; import java.util.Scanner; public class Client { @@ -20,7 +21,7 @@ public Client() throws IOException { new Thread(() -> { try { - while (true) { + while (!socket.isClosed()) { String message = in.readUTF(); if (message.startsWith("/")) { if (message.equalsIgnoreCase("/exitok")) { @@ -45,9 +46,13 @@ public Client() throws IOException { } }).start(); - while (true) { + while (!socket.isClosed()) { String message = scanner.nextLine(); - out.writeUTF(message); + try { + out.writeUTF(message); + } catch (SocketException e) { + System.out.println("Вы были отключены от сервера."); + } if (message.equalsIgnoreCase("/exit")) { break; } From 76ecfa561e985a7e3de6dc2b1ed98acd1b41b31f Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 12:57:39 +0300 Subject: [PATCH 13/40] =?UTF-8?q?=D0=90=D1=83=D1=82=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D0=BC=D0=B8=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BA=D0=B0=D0=BC=D0=B8=20=D0=B1=D0=B5=D0=B7?= =?UTF-8?q?=20=D0=BF=D0=B0=D1=80=D1=81=D0=B8=D0=BD=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ClientHandler.java | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index ef117d0..9503645 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -27,33 +27,43 @@ public ClientHandler(Socket socket, Server server) throws IOException { System.out.println("Клиент подключился " + socket.getPort()); //Цикл логина while (true) { - sendMsg("Для начала работы надо пройти аутентификацию. Формат команды /log login password\n" + - "или регистрацию. Формат команды /reg username login password "); + sendMsg("Для начала работы надо пройти аутентификацию или регистрацию\n" + + "Формат команды для аутентификации: /log\n" + + "Формат команды для регистрации: /reg\n" + + "Для выхода используйте комманду /exit"); String message = in.readUTF(); if (message.startsWith("/")) { if (message.equals("/exit")) { sendMsg("/exitOK"); break; } - String[] tokens = message.split(" "); - if (tokens[0].equals("/log")) { - if (tokens.length != 3) { - sendMsg("Ошибка авторизации"); - continue; - } + if (message.equalsIgnoreCase("/log")) { + String[] loginData = new String[2]; + sendMsg("Введите логин: "); + loginData[0] = in.readUTF(); + sendMsg("Введите пароль: "); + loginData[1] = in.readUTF(); if (server.getAuthenticator() - .authenticate(this, tokens[1], tokens[2])) { + .authenticate(this, loginData[0], loginData[1])) { break; - } - } - if (tokens[0].equals("/reg")) { - if (tokens.length != 4) { - sendMsg("Неверный формат команды /reg"); + } else { + sendMsg("Ошибка авторизации!"); continue; } + } + if (message.equalsIgnoreCase("/reg")) { + String[] regData = new String[3]; + sendMsg("Введите никнейм: "); + regData[0] = in.readUTF(); + sendMsg("Введите логин: "); + regData[1] = in.readUTF(); + sendMsg("Введите пароль: "); + regData[2] = in.readUTF(); if (server.getAuthenticator() - .registration(this, tokens[1], tokens[2], tokens[3])) { - break; + .registration(this, regData[0], regData[1], regData[2])) { + break; + } else { + sendMsg("Ошибка регистрации!"); } } } From a1aafbe65082c73ce3a2acefc5204d2c38bf7cf9 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 14:03:30 +0300 Subject: [PATCH 14/40] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20DatabaseManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/project/database/DatabaseManager.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Server/src/main/java/ru/project/database/DatabaseManager.java diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java new file mode 100644 index 0000000..935f936 --- /dev/null +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -0,0 +1,24 @@ +package ru.project.database; + +import java.sql.*; + +public class DatabaseManager { + private static final String DB_URL = "jdbc:sqlite:chat.db"; + + public DatabaseManager() { + try (Connection conn = DriverManager.getConnection(DB_URL); + Statement stmt = conn.createStatement()) { + String createTableSQL = """ + CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + password TEXT NOT NULL, + role TEXT NOT NULL + ); + """; + stmt.execute(createTableSQL); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} From 4712e33aa3f276e653165d730605644dd2501ad4 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 14:42:49 +0300 Subject: [PATCH 15/40] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20DatabaseManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dataSources.xml | 18 +++++++ .idea/sqldialects.xml | 7 +++ .../ru/project/database/DatabaseManager.java | 49 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/sqldialects.xml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..2bfbbd0 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,18 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/postgres + + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..a7c53a0 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java index 935f936..b4f9ad9 100644 --- a/Server/src/main/java/ru/project/database/DatabaseManager.java +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -12,6 +12,7 @@ public DatabaseManager() { CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, username TEXT NOT NULL UNIQUE, + login TEXT NOT NULL UNIQUE, password TEXT NOT NULL, role TEXT NOT NULL ); @@ -21,4 +22,52 @@ CREATE TABLE IF NOT EXISTS users ( e.printStackTrace(); } } + public String authenticate(String login, String hashedPassword) { + String query = "SELECT username FROM users WHERE login = ? AND password = ?"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(query)) { + pstmt.setString(1, login); + pstmt.setString(2, hashedPassword); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return rs.getString("username"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + public boolean registerUser(String username, String login, String hashedPassword, String role) { + String query = "INSERT INTO users (username, login, password, role) VALUES (?, ?, ?, ?)"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(query)) { + pstmt.setString(1, username); + pstmt.setString(2, login); + pstmt.setString(3, hashedPassword); + pstmt.setString(4, role.toUpperCase()); + pstmt.executeUpdate(); + return true; + } catch (SQLException e) { + if (e.getMessage().contains("UNIQUE")) { + System.out.println("Логин или имя пользователя уже существуют."); + } else { + e.printStackTrace(); + } + return false; + } + } + public String getUserRole(String username) { + String query = "SELECT role FROM users WHERE username = ?"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(query)) { + pstmt.setString(1, username); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return rs.getString("role"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } } From 75ca6a797d723124eba8b1c27dc86d49f488d221 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 16:03:00 +0300 Subject: [PATCH 16/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=85=D0=BE=D0=B4=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BA=20=D0=B2=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B5=20?= =?UTF-8?q?inMemoryAuthenticator,=20=D0=B0=20=D1=82=D0=B0=D0=BA=D0=B6?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0=20registerUser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/project/database/DatabaseManager.java | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java index b4f9ad9..5678ace 100644 --- a/Server/src/main/java/ru/project/database/DatabaseManager.java +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -1,9 +1,11 @@ package ru.project.database; +import ru.project.Role; import java.sql.*; public class DatabaseManager { - private static final String DB_URL = "jdbc:sqlite:chat.db"; + private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=postgres&password=admin"; + public DatabaseManager() { try (Connection conn = DriverManager.getConnection(DB_URL); @@ -22,12 +24,12 @@ CREATE TABLE IF NOT EXISTS users ( e.printStackTrace(); } } - public String authenticate(String login, String hashedPassword) { + public String authenticate(String login, String password) { String query = "SELECT username FROM users WHERE login = ? AND password = ?"; try (Connection conn = DriverManager.getConnection(DB_URL); PreparedStatement pstmt = conn.prepareStatement(query)) { pstmt.setString(1, login); - pstmt.setString(2, hashedPassword); + pstmt.setString(2, password); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { return rs.getString("username"); @@ -37,14 +39,14 @@ public String authenticate(String login, String hashedPassword) { } return null; } - public boolean registerUser(String username, String login, String hashedPassword, String role) { + public boolean registerUser(String username, String login, String password, Role role) { String query = "INSERT INTO users (username, login, password, role) VALUES (?, ?, ?, ?)"; try (Connection conn = DriverManager.getConnection(DB_URL); PreparedStatement pstmt = conn.prepareStatement(query)) { pstmt.setString(1, username); pstmt.setString(2, login); - pstmt.setString(3, hashedPassword); - pstmt.setString(4, role.toUpperCase()); + pstmt.setString(3, password); + pstmt.setString(4, String.valueOf(role)); pstmt.executeUpdate(); return true; } catch (SQLException e) { @@ -70,4 +72,43 @@ public String getUserRole(String username) { } return null; } + public boolean isUsernameAlreadyExist(String username) { + String query = "SELECT 1 FROM users WHERE username = ?"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(query)) { + pstmt.setString(1, username); + ResultSet rs = pstmt.executeQuery(); + return rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + public boolean isLoginAlreadyExist(String login) { + String query = "SELECT 1 FROM users WHERE login = ?"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(query)) { + pstmt.setString(1, login); + ResultSet rs = pstmt.executeQuery(); + return rs.next(); + } catch (SQLException e) { + e.printStackTrace(); + return false; + } + } + public String getUsernameByLoginAndPassword(String login, String password) { + String query = "SELECT username FROM users WHERE username = ? AND password = ?"; + try (Connection conn = DriverManager.getConnection(DB_URL); + PreparedStatement pstmt = conn.prepareStatement(query)) { + pstmt.setString(1, login); + pstmt.setString(2, password); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return rs.getString("username"); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } } From c57ec64a0a3c8664ecf8ef207a71cb0e8eb2f847 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 16:03:38 +0300 Subject: [PATCH 17/40] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B0=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B8=20=D0=B0=D1=83=D1=82=D0=B5=D0=BD=D1=82=D0=B8?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=B1=D0=B0?= =?UTF-8?q?=D0=B7=D0=BE=D0=B9=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ru/project/inMemoryAuthenticator.java | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index a796a05..0437600 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -26,18 +26,9 @@ public inMemoryAuthenticator(Server server) { public void initialize() { System.out.println("Инициализация"); } - private String getUsernameByLoginAndPassword(String login, String password) { - for (User u : users) { - if (u.login.equals(login) && u.password.equals(password)) { - return u.username; - } - } - return null; - } - @Override public boolean authenticate(ClientHandler clientHandler, String login, String password) { - String username = getUsernameByLoginAndPassword(login, password); + String username = server.getDatabaseManager().getUsernameByLoginAndPassword(login, password); if (username == null) { clientHandler.sendMsg("Неверный логин и/или пароль"); return false; @@ -46,8 +37,8 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa clientHandler.sendMsg("Данный пользователь уже в сети"); return false; } - clientHandler.setUsername(username); - if (clientHandler.getUsername().equals("admin")) { + clientHandler.setUsername(server.getDatabaseManager().authenticate(login, password)); + if (server.getDatabaseManager().getUserRole(clientHandler.getUsername()).equals(Role.ADMIN)) { clientHandler.setRole(Role.ADMIN); } else { clientHandler.setRole(Role.USER); @@ -56,36 +47,21 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa clientHandler.sendMsg("/authOK " + username); return true; } - private boolean isLoginAlreadyExist(String login) { - for (User u : users) { - if (u.login.equals(login)) { - return true; - } - } - return false; - } - private boolean isUsernameAlreadyExist(String username) { - for (User u : users) { - if (u.username.equals(username)) { - return true; - } - } - return false; - } @Override public boolean registration(ClientHandler clientHandler, String username, String login, String password) { if (login.length() < 3 || password.length() < 3 || username.length() < 3) { clientHandler.sendMsg("Логин 3+ символа, пароль 3+ символа, имя пользователя 3+ символа"); return false; } - if (isLoginAlreadyExist(login)) { + if (server.getDatabaseManager().isLoginAlreadyExist(login)) { clientHandler.sendMsg("Такой логин уже используется"); return false; } - if (isUsernameAlreadyExist(username)) { + if (server.getDatabaseManager().isUsernameAlreadyExist(username)) { clientHandler.sendMsg("Такое имя пользователя уже используется"); return false; } + server.getDatabaseManager().registerUser(username, login, password, Role.USER); users.add(new User(username, login, password)); clientHandler.setUsername(username); if (clientHandler.getUsername().equals("admin")) { @@ -97,5 +73,4 @@ public boolean registration(ClientHandler clientHandler, String username, String clientHandler.sendMsg("/regOK " + username); return true; } - } From c699787320803c456f770880a38ababe3aed2b59 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 16:04:03 +0300 Subject: [PATCH 18/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20DatabaseManager=20=D0=BA=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/Server.java | 11 ++++++++++- .../src/main/java/ru/project/ServerApplication.java | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 8601691..7dd3c28 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -1,5 +1,8 @@ package ru.project; +import ru.project.database.DatabaseManager; + +import javax.xml.crypto.Data; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; @@ -11,9 +14,11 @@ public class Server { private int port; private List clients; private Authenticator authenticator; + private final DatabaseManager databaseManager; - public Server(int port) { + public Server(int port, DatabaseManager databaseManager) { this.port = port; + this.databaseManager = databaseManager; clients = new CopyOnWriteArrayList<>(); authenticator = new inMemoryAuthenticator(this); } @@ -81,4 +86,8 @@ public void kickUser(String usernameToKick, ClientHandler adminHandler) { adminHandler.sendMsg("Недостаточно прав"); } } + + public DatabaseManager getDatabaseManager() { + return databaseManager; + } } diff --git a/Server/src/main/java/ru/project/ServerApplication.java b/Server/src/main/java/ru/project/ServerApplication.java index 2dbdb42..f44d85c 100644 --- a/Server/src/main/java/ru/project/ServerApplication.java +++ b/Server/src/main/java/ru/project/ServerApplication.java @@ -1,7 +1,9 @@ package ru.project; +import ru.project.database.DatabaseManager; + public class ServerApplication { public static void main(String[] args) { - new Server(8189).start(); + new Server(8189, new DatabaseManager()).start(); } } From c0d2c1d6d856043fb2be8d61b84c52ce74de6e4d Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 16:04:14 +0300 Subject: [PATCH 19/40] =?UTF-8?q?=D0=97=D0=B0=D0=B2=D0=B8=D1=81=D0=B8?= =?UTF-8?q?=D0=BC=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7271f2e..4e0fbfe 100644 --- a/pom.xml +++ b/pom.xml @@ -12,11 +12,19 @@ Server Client - + + + + org.postgresql + postgresql + 42.7.4 + + 23 23 UTF-8 + \ No newline at end of file From 81b140b12b4d81d0baba170f2fae9932dd52100b Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 16:14:31 +0300 Subject: [PATCH 20/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20admin=20=D0=BF=D1=80=D0=B8=20=D1=81?= =?UTF-8?q?=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B8=20=D1=82=D0=B0=D0=B1?= =?UTF-8?q?=D0=BB=D0=B8=D1=86=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/ru/project/database/DatabaseManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java index 5678ace..77c1138 100644 --- a/Server/src/main/java/ru/project/database/DatabaseManager.java +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -19,7 +19,13 @@ CREATE TABLE IF NOT EXISTS users ( role TEXT NOT NULL ); """; + String addAdmin = """ + INSERT INTO users (username, login, password, role) + SELECT 'admin', 'admin', 'admin', 'ADMIN' + WHERE NOT EXISTS (SELECT 1 FROM users WHERE username = 'admin'); + """; stmt.execute(createTableSQL); + stmt.executeUpdate(addAdmin); } catch (SQLException e) { e.printStackTrace(); } From 956d4135d11b1acd6dc2c73b70f3e87c105c6457 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 12 Jan 2025 16:21:49 +0300 Subject: [PATCH 21/40] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BD=D0=B0=20admin,=20=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/inMemoryAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index 0437600..24171ac 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -38,7 +38,7 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa return false; } clientHandler.setUsername(server.getDatabaseManager().authenticate(login, password)); - if (server.getDatabaseManager().getUserRole(clientHandler.getUsername()).equals(Role.ADMIN)) { + if (server.getDatabaseManager().getUserRole(username).equals("ADMIN")) { clientHandler.setRole(Role.ADMIN); } else { clientHandler.setRole(Role.USER); From 3f1f125ef94b0ef6609e144acf530d661fce23b5 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Tue, 21 Jan 2025 23:49:05 +0300 Subject: [PATCH 22/40] =?UTF-8?q?=D0=A3=D0=B3=D0=BB=D1=83=D0=B1=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D0=B0=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20username?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ClientHandler.java | 4 +++- .../java/ru/project/inMemoryAuthenticator.java | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 9503645..e05c8f7 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -53,7 +53,9 @@ public ClientHandler(Socket socket, Server server) throws IOException { } if (message.equalsIgnoreCase("/reg")) { String[] regData = new String[3]; - sendMsg("Введите никнейм: "); + sendMsg("Введите никнейм.\n" + + "Никнейм не должен содержать более 20 символов, и не менее 5 символов\n" + + "Можно использовать цифры, латинские буквы и знаки \"_\" и \"-\""); regData[0] = in.readUTF(); sendMsg("Введите логин: "); regData[1] = in.readUTF(); diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index 24171ac..ec2ef8e 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -1,5 +1,6 @@ package ru.project; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -49,6 +50,23 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa } @Override public boolean registration(ClientHandler clientHandler, String username, String login, String password) { + if (username.length() < 5) { + clientHandler.sendMsg("Имя пользователя должно содержать не менее 5 символов."); + return false; + } + if (username.length() > 20) { + clientHandler.sendMsg("Имя пользователя не должно содержать более 20 символов."); + return false; + } + char[] usernameChars = new char[username.length()]; + for (int i = 0; i < username.length(); i++) { + usernameChars[i] = username.charAt(i); + } + //List + //boolean contains = Arrays.stream(usernameChars).anyMatch() + //if (Arrays.asList(usernameChars).contains() + //) + if (login.length() < 3 || password.length() < 3 || username.length() < 3) { clientHandler.sendMsg("Логин 3+ символа, пароль 3+ символа, имя пользователя 3+ символа"); return false; From bd5fe367b7261527fce147be76467cdba3289b00 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Wed, 22 Jan 2025 00:01:15 +0300 Subject: [PATCH 23/40] =?UTF-8?q?=D0=A2=D1=80=D0=B5=D0=B1=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D1=82=D0=B5=D0=BB=D1=8F,=20=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B8=20=D0=BF=D0=B0=D1=80=D0=BE=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8.=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B3=D1=83=D0=BB=D1=8F=D1=80=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ClientHandler.java | 7 ++++-- .../ru/project/inMemoryAuthenticator.java | 23 +++++++------------ 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index e05c8f7..2fec94d 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -57,9 +57,12 @@ public ClientHandler(Socket socket, Server server) throws IOException { "Никнейм не должен содержать более 20 символов, и не менее 5 символов\n" + "Можно использовать цифры, латинские буквы и знаки \"_\" и \"-\""); regData[0] = in.readUTF(); - sendMsg("Введите логин: "); + sendMsg("Введите логин.\n" + + "Логин не должен содержать более 20 символов, и не менее 5 символов\n" + + "Можно использовать цифры, латинские буквы и знаки \"_\" и \"-\""); regData[1] = in.readUTF(); - sendMsg("Введите пароль: "); + sendMsg("Введите пароль.\n" + + "Пароль должен содержать от 5 до 20 символов и обязательно включать в себя любой специальный символ."); regData[2] = in.readUTF(); if (server.getAuthenticator() .registration(this, regData[0], regData[1], regData[2])) { diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index ec2ef8e..18b8012 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -50,25 +50,18 @@ public boolean authenticate(ClientHandler clientHandler, String login, String pa } @Override public boolean registration(ClientHandler clientHandler, String username, String login, String password) { - if (username.length() < 5) { - clientHandler.sendMsg("Имя пользователя должно содержать не менее 5 символов."); + String regex = "^[a-zA-Z0-9_-]{5,20}$"; + String regexForPassword = "^(?=.*[!@#$%^&*(),.?\":{}|<>])[a-zA-Z0-9!@#$%^&*(),.?\":{}|<>]{5,20}$"; + if(!username.matches(regex)) { + clientHandler.sendMsg("Убедитесь, что имя пользователя соответствует требованиям"); return false; } - if (username.length() > 20) { - clientHandler.sendMsg("Имя пользователя не должно содержать более 20 символов."); + if(!login.matches(regex)) { + clientHandler.sendMsg("Убедитесь, что логин соответствует требованиям"); return false; } - char[] usernameChars = new char[username.length()]; - for (int i = 0; i < username.length(); i++) { - usernameChars[i] = username.charAt(i); - } - //List - //boolean contains = Arrays.stream(usernameChars).anyMatch() - //if (Arrays.asList(usernameChars).contains() - //) - - if (login.length() < 3 || password.length() < 3 || username.length() < 3) { - clientHandler.sendMsg("Логин 3+ символа, пароль 3+ символа, имя пользователя 3+ символа"); + if (!password.matches(regexForPassword)) { + clientHandler.sendMsg("Убедитесь, что пароль соответствует требованиям"); return false; } if (server.getDatabaseManager().isLoginAlreadyExist(login)) { From c3a0e3869e2b3e6ba301b40b11a3c8e9c8762064 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Thu, 13 Feb 2025 23:25:47 +0300 Subject: [PATCH 24/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=20=D0=BA=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 2fec94d..6a8af18 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -6,6 +6,8 @@ import java.io.IOException; import java.net.Socket; import java.net.SocketException; +import java.text.SimpleDateFormat; +import java.util.Date; public class ClientHandler { @@ -101,7 +103,8 @@ public ClientHandler(Socket socket, Server server) throws IOException { server.kickUser(tokens[1], this); } } else { - server.broadcastMessage(username + " : " + message); + String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; + server.broadcastMessage(messageWithTime); } } } catch (IOException e) { @@ -158,4 +161,7 @@ public void setRole(Role role) { public Role getRole() { return role; } + private String getCurrentTime() { + return new SimpleDateFormat("HH:mm:ss").format(new Date()); + } } From a2dc16671567a8e0b9535f5e3522bf8f7f904b7e Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sat, 15 Feb 2025 20:39:52 +0000 Subject: [PATCH 25/40] =?UTF-8?q?=D0=91=D0=B0=D0=BD=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F.=20?= =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D1=80=D0=B0=D0=B7=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 3 +++ Server/src/main/java/ru/project/ClientHandler.java | 12 +++++++++++- Server/src/main/java/ru/project/Server.java | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 7d6df0d..79839de 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -35,6 +35,9 @@ public Client() throws IOException { System.out.println("Регистрация прошла успешно! Имя пользователя: " + message.split(" ")[1]); } + if (message.equalsIgnoreCase("/banok")) { + + } } else { System.out.println(message); } diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 6a8af18..3ee2899 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -102,7 +102,17 @@ public ClientHandler(Socket socket, Server server) throws IOException { } server.kickUser(tokens[1], this); } - } else { + } else if (message.startsWith("/ban ")) { + String[] tokens = message.split(" ", 2); + if (tokens.length != 2) { + sendMsg("Неверный формат команды /ban"); + continue; + } + server.banUser(tokens[1], this); + } + + + else { String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; server.broadcastMessage(messageWithTime); } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 7dd3c28..2d21912 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -86,6 +86,20 @@ public void kickUser(String usernameToKick, ClientHandler adminHandler) { adminHandler.sendMsg("Недостаточно прав"); } } + public void banUser(String usernameToBan, ClientHandler adminHandler) { + if (adminHandler.getRole().equals(Role.ADMIN)) { + for (ClientHandler client : client) { + if (client.getUsername().equals(usernameToBan)) { + client.sendMsg("/banok"); + broadcastMessage("Пользователь " + usernameToBan + " был забанен администратором"); + return; + } + } + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToBan + " не найден"); + } else { + adminHandler.sendMsg("Недостаточно прав"); + } + } public DatabaseManager getDatabaseManager() { return databaseManager; From aad311f5f1889ff99f7924d37aebd3ade2db3c06 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Thu, 13 Feb 2025 23:25:47 +0300 Subject: [PATCH 26/40] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=20=D0=BA=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/ClientHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 2fec94d..6a8af18 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -6,6 +6,8 @@ import java.io.IOException; import java.net.Socket; import java.net.SocketException; +import java.text.SimpleDateFormat; +import java.util.Date; public class ClientHandler { @@ -101,7 +103,8 @@ public ClientHandler(Socket socket, Server server) throws IOException { server.kickUser(tokens[1], this); } } else { - server.broadcastMessage(username + " : " + message); + String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; + server.broadcastMessage(messageWithTime); } } } catch (IOException e) { @@ -158,4 +161,7 @@ public void setRole(Role role) { public Role getRole() { return role; } + private String getCurrentTime() { + return new SimpleDateFormat("HH:mm:ss").format(new Date()); + } } From 1a01030c977ebbdfaae019c97863a4885b1417ba Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sat, 15 Feb 2025 20:39:52 +0000 Subject: [PATCH 27/40] =?UTF-8?q?=D0=91=D0=B0=D0=BD=20=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F.=20?= =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D0=BE=20=D1=80=D0=B0=D0=B7=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 3 +++ Server/src/main/java/ru/project/ClientHandler.java | 12 +++++++++++- Server/src/main/java/ru/project/Server.java | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 7d6df0d..79839de 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -35,6 +35,9 @@ public Client() throws IOException { System.out.println("Регистрация прошла успешно! Имя пользователя: " + message.split(" ")[1]); } + if (message.equalsIgnoreCase("/banok")) { + + } } else { System.out.println(message); } diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 6a8af18..3ee2899 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -102,7 +102,17 @@ public ClientHandler(Socket socket, Server server) throws IOException { } server.kickUser(tokens[1], this); } - } else { + } else if (message.startsWith("/ban ")) { + String[] tokens = message.split(" ", 2); + if (tokens.length != 2) { + sendMsg("Неверный формат команды /ban"); + continue; + } + server.banUser(tokens[1], this); + } + + + else { String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; server.broadcastMessage(messageWithTime); } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 7dd3c28..2d21912 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -86,6 +86,20 @@ public void kickUser(String usernameToKick, ClientHandler adminHandler) { adminHandler.sendMsg("Недостаточно прав"); } } + public void banUser(String usernameToBan, ClientHandler adminHandler) { + if (adminHandler.getRole().equals(Role.ADMIN)) { + for (ClientHandler client : client) { + if (client.getUsername().equals(usernameToBan)) { + client.sendMsg("/banok"); + broadcastMessage("Пользователь " + usernameToBan + " был забанен администратором"); + return; + } + } + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToBan + " не найден"); + } else { + adminHandler.sendMsg("Недостаточно прав"); + } + } public DatabaseManager getDatabaseManager() { return databaseManager; From 2e5142c94e2175decd6a901c8690446e07951c70 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 16 Feb 2025 22:54:23 +0300 Subject: [PATCH 28/40] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=B1=D0=B0=D0=BD=D0=B0=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 8 ++++++-- .../src/main/java/ru/project/ClientHandler.java | 16 +++++++--------- Server/src/main/java/ru/project/Server.java | 2 +- .../ru/project/database/DatabaseManager.java | 2 +- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 79839de..04ff082 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -12,6 +12,7 @@ public class Client { private DataOutputStream out; private DataInputStream in; private Scanner scanner; + private boolean isBanned = false; public Client() throws IOException { scanner = new Scanner(System.in); @@ -36,7 +37,8 @@ public Client() throws IOException { + message.split(" ")[1]); } if (message.equalsIgnoreCase("/banok")) { - + isBanned = true; + System.out.println("Вы были заблокированы администратором."); } } else { System.out.println(message); @@ -52,7 +54,9 @@ public Client() throws IOException { while (!socket.isClosed()) { String message = scanner.nextLine(); try { - out.writeUTF(message); + if (!isBanned) { + out.writeUTF(message); + } else System.out.println("Вы не можете писать сообщения."); } catch (SocketException e) { System.out.println("Вы были отключены от сервера."); } diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 3ee2899..1b24027 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -101,17 +101,15 @@ public ClientHandler(Socket socket, Server server) throws IOException { continue; } server.kickUser(tokens[1], this); + } else if (message.startsWith("/ban ")) { + String[] tokens = message.split(" ", 2); + if (tokens.length != 2) { + sendMsg("Неверный формат команды /ban"); + continue; + } + server.banUser(tokens[1], this); } - } else if (message.startsWith("/ban ")) { - String[] tokens = message.split(" ", 2); - if (tokens.length != 2) { - sendMsg("Неверный формат команды /ban"); - continue; - } - server.banUser(tokens[1], this); } - - else { String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; server.broadcastMessage(messageWithTime); diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 2d21912..42d54c9 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -88,7 +88,7 @@ public void kickUser(String usernameToKick, ClientHandler adminHandler) { } public void banUser(String usernameToBan, ClientHandler adminHandler) { if (adminHandler.getRole().equals(Role.ADMIN)) { - for (ClientHandler client : client) { + for (ClientHandler client : clients) { if (client.getUsername().equals(usernameToBan)) { client.sendMsg("/banok"); broadcastMessage("Пользователь " + usernameToBan + " был забанен администратором"); diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java index 77c1138..a9bb845 100644 --- a/Server/src/main/java/ru/project/database/DatabaseManager.java +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -4,7 +4,7 @@ import java.sql.*; public class DatabaseManager { - private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=postgres&password=admin"; + private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=postgres&password=postgres"; public DatabaseManager() { From 002f4f4214953da755662c7dcfd33d3f38eb508f Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 16 Feb 2025 22:56:21 +0300 Subject: [PATCH 29/40] =?UTF-8?q?=D0=A7=D0=B8=D1=81=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ClientHandler.java | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 1b24027..22ff6de 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -2,19 +2,17 @@ import java.io.DataInputStream; import java.io.DataOutputStream; -import java.io.EOFException; import java.io.IOException; import java.net.Socket; -import java.net.SocketException; import java.text.SimpleDateFormat; import java.util.Date; public class ClientHandler { - private Socket socket; - private Server server; - private DataInputStream in; - private DataOutputStream out; + private final Socket socket; + private final Server server; + private final DataInputStream in; + private final DataOutputStream out; private String username; private Role role; @@ -29,10 +27,11 @@ public ClientHandler(Socket socket, Server server) throws IOException { System.out.println("Клиент подключился " + socket.getPort()); //Цикл логина while (true) { - sendMsg("Для начала работы надо пройти аутентификацию или регистрацию\n" + - "Формат команды для аутентификации: /log\n" + - "Формат команды для регистрации: /reg\n" + - "Для выхода используйте комманду /exit"); + sendMsg(""" + Для начала работы надо пройти аутентификацию или регистрацию + Формат команды для аутентификации: /log + Формат команды для регистрации: /reg + Для выхода используйте комманду /exit"""); String message = in.readUTF(); if (message.startsWith("/")) { if (message.equals("/exit")) { @@ -55,13 +54,15 @@ public ClientHandler(Socket socket, Server server) throws IOException { } if (message.equalsIgnoreCase("/reg")) { String[] regData = new String[3]; - sendMsg("Введите никнейм.\n" + - "Никнейм не должен содержать более 20 символов, и не менее 5 символов\n" + - "Можно использовать цифры, латинские буквы и знаки \"_\" и \"-\""); + sendMsg(""" + Введите никнейм. + Никнейм не должен содержать более 20 символов, и не менее 5 символов + Можно использовать цифры, латинские буквы и знаки "_" и "-\""""); regData[0] = in.readUTF(); - sendMsg("Введите логин.\n" + - "Логин не должен содержать более 20 символов, и не менее 5 символов\n" + - "Можно использовать цифры, латинские буквы и знаки \"_\" и \"-\""); + sendMsg(""" + Введите логин. + Логин не должен содержать более 20 символов, и не менее 5 символов + Можно использовать цифры, латинские буквы и знаки "_" и "-\""""); regData[1] = in.readUTF(); sendMsg("Введите пароль.\n" + "Пароль должен содержать от 5 до 20 символов и обязательно включать в себя любой специальный символ."); From 77a5cf3d6709c8a52b06dc0710ba1b8cc7cbf22e Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sun, 16 Feb 2025 23:07:18 +0300 Subject: [PATCH 30/40] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B7=D0=B1=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/Client.java | 4 ++++ Server/src/main/java/ru/project/ClientHandler.java | 13 +++++++++++++ Server/src/main/java/ru/project/Server.java | 14 ++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Client/src/main/java/ru/project/Client.java b/Client/src/main/java/ru/project/Client.java index 04ff082..5d7f515 100644 --- a/Client/src/main/java/ru/project/Client.java +++ b/Client/src/main/java/ru/project/Client.java @@ -40,6 +40,10 @@ public Client() throws IOException { isBanned = true; System.out.println("Вы были заблокированы администратором."); } + if (message.equalsIgnoreCase("/unbanok")) { + isBanned = false; + System.out.println("Теперь вы не заблокированы. Вам доступна отправка сообщений в чат."); + } } else { System.out.println(message); } diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 22ff6de..9a87e62 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -82,6 +82,7 @@ public ClientHandler(Socket socket, Server server) throws IOException { //Цикл работы while (true) { String message = in.readUTF(); + boolean targetUserIsBanned = false; if (message.startsWith("/")) { if (message.equalsIgnoreCase("/exit")) { sendMsg("/exitok"); @@ -109,6 +110,18 @@ public ClientHandler(Socket socket, Server server) throws IOException { continue; } server.banUser(tokens[1], this); + targetUserIsBanned = true; + } else if (message.startsWith("/unban ")) { + String[] tokens = message.split(" ", 2); + if (tokens.length != 2) { + sendMsg("Неверный формат комманды /unban"); + continue; + } + if (targetUserIsBanned) { + server.unbanUser(tokens[1], this); + targetUserIsBanned = false; + } else sendMsg("Пользователь " + tokens[1] + " не находится в бане"); + } } else { diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 42d54c9..979ae3b 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -100,6 +100,20 @@ public void banUser(String usernameToBan, ClientHandler adminHandler) { adminHandler.sendMsg("Недостаточно прав"); } } + public void unbanUser(String usernameToUnban, ClientHandler adminHandler) { + if (adminHandler.getRole().equals(Role.ADMIN)) { + for (ClientHandler client : clients) { + if (client.getUsername().equals(usernameToUnban)) { + client.sendMsg("/unbanok"); + broadcastMessage("Пользователь " + usernameToUnban + " был разбанен администратором"); + return; + } + } + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToUnban + " не найден"); + } else { + adminHandler.sendMsg("Недостаточно прав"); + } + } public DatabaseManager getDatabaseManager() { return databaseManager; From fb7970e4d39c0708a649bfec24721b538c696e30 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Tue, 18 Feb 2025 22:03:00 +0300 Subject: [PATCH 31/40] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=D0=B4=D0=BD=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D0=B8=20=D0=B8=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BD=D0=B5=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ClientHandler.java | 10 +++++- Server/src/main/java/ru/project/Server.java | 14 ++++++++ .../java/ru/project/checktime/CheckTime.java | 35 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 Server/src/main/java/ru/project/checktime/CheckTime.java diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index c86d631..cdcb595 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -15,12 +15,14 @@ public class ClientHandler { private final DataOutputStream out; private String username; private Role role; + private long lastActiveTime; public ClientHandler(Socket socket, Server server) throws IOException { this.socket = socket; this.server = server; this.in = new DataInputStream(socket.getInputStream()); this.out = new DataOutputStream(socket.getOutputStream()); + this.lastActiveTime = System.currentTimeMillis(); new Thread(() -> { try { @@ -121,7 +123,9 @@ public ClientHandler(Socket socket, Server server) throws IOException { server.unbanUser(tokens[1], this); targetUserIsBanned = false; } else sendMsg("Пользователь " + tokens[1] + " не находится в бане"); - } + } else if (message.equalsIgnoreCase("/online")) { + sendMsg(server.getOnlineUsers()); + } } else { String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; @@ -185,4 +189,8 @@ public Role getRole() { private String getCurrentTime() { return new SimpleDateFormat("HH:mm:ss").format(new Date()); } + + public long getLastActiveTime() { + return lastActiveTime; + } } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 5dfe3f3..40a4f29 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -1,5 +1,6 @@ package ru.project; +import ru.project.checktime.CheckTime; import ru.project.database.DatabaseManager; import javax.xml.crypto.Data; @@ -21,6 +22,8 @@ public Server(int port, DatabaseManager databaseManager) { this.databaseManager = databaseManager; clients = new CopyOnWriteArrayList<>(); authenticator = new inMemoryAuthenticator(this); + + new CheckTime(this).start(); } public void start(){ @@ -117,4 +120,15 @@ public void unbanUser(String usernameToUnban, ClientHandler adminHandler) { public DatabaseManager getDatabaseManager() { return databaseManager; } + + public String getOnlineUsers() { + StringBuilder sb = new StringBuilder("Сейчас онлайн:\n"); + for (ClientHandler client : clients) { + sb.append(client.getUsername()).append("\n"); + } + return sb.toString(); + } + public List getClients() { + return this.clients; + } } diff --git a/Server/src/main/java/ru/project/checktime/CheckTime.java b/Server/src/main/java/ru/project/checktime/CheckTime.java new file mode 100644 index 0000000..3af8b5c --- /dev/null +++ b/Server/src/main/java/ru/project/checktime/CheckTime.java @@ -0,0 +1,35 @@ +package ru.project.checktime; + +import ru.project.*; + +import java.util.ArrayList; + +public class CheckTime extends Thread { + private static final long TIMEOUT = 20 * 60 * 1000; + private Server server; + private ClientHandler clientHandler; + + public CheckTime(Server server) { + this.server = server; + } + @Override + public void run() { + while (true) { + try { + Thread.sleep(60*1000); + long currentTime = System.currentTimeMillis(); + + for (ClientHandler client : server.getClients()) { + if (currentTime - client.getLastActiveTime() > TIMEOUT) { + System.out.println("Отключение неактивного клиента: " + client.getUsername()); + client.sendMsg("/exitok"); + server.unsubscribe(client); + client.disconnect(); + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} From 496cdd64bac1828baab790663f3b71c0bf6df86f Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Wed, 19 Feb 2025 23:29:42 +0300 Subject: [PATCH 32/40] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ChatClientGUI.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Client/src/main/java/ru/project/ChatClientGUI.java diff --git a/Client/src/main/java/ru/project/ChatClientGUI.java b/Client/src/main/java/ru/project/ChatClientGUI.java new file mode 100644 index 0000000..2f31496 --- /dev/null +++ b/Client/src/main/java/ru/project/ChatClientGUI.java @@ -0,0 +1,27 @@ +package ru.project; +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +public class ChatClientGUI extends Application { + + @Override + public void start(Stage primaryStage) { + TextField inputField = new TextField(); + inputField.setPromptText("Введите сообщение..."); + Button sendButton = new Button("Отправить"); + VBox root = new VBox(10, inputField, sendButton); + Scene scene = new Scene(root, 400, 300); + + primaryStage.setTitle("Чат-клиент"); + primaryStage.setScene(scene); + primaryStage.show(); + } + + public static void main(String[] args) { + launch(args); + } +} From c48d6ba0f9cb3be203494ba11dd1c2fe4942bc04 Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Thu, 20 Feb 2025 00:26:12 +0300 Subject: [PATCH 33/40] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81:=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Client/pom.xml b/Client/pom.xml index e7ad365..d00cd2a 100644 --- a/Client/pom.xml +++ b/Client/pom.xml @@ -17,4 +17,17 @@ UTF-8 + + + org.openjfx + javafx-controls + 23.0.2 + + + org.openjfx + javafx-base + 23.0.2 + + + \ No newline at end of file From c1a1897e7c03448f68ba5009c49dda4d3b9faccf Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Thu, 20 Feb 2025 00:35:56 +0300 Subject: [PATCH 34/40] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81:=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81?= =?UTF-8?q?=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ChatClientGUI.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Client/src/main/java/ru/project/ChatClientGUI.java b/Client/src/main/java/ru/project/ChatClientGUI.java index 2f31496..b6179a0 100644 --- a/Client/src/main/java/ru/project/ChatClientGUI.java +++ b/Client/src/main/java/ru/project/ChatClientGUI.java @@ -1,18 +1,28 @@ package ru.project; import javafx.application.Application; import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.TextField; +import javafx.scene.control.*; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class ChatClientGUI extends Application { + private TextArea chatArea; + private TextField inputField; + private Button sendButton; @Override public void start(Stage primaryStage) { + chatArea = new TextArea(); + chatArea.setEditable(false); + chatArea.setWrapText(true); + TextField inputField = new TextField(); inputField.setPromptText("Введите сообщение..."); + Button sendButton = new Button("Отправить"); + + sendButton.setOnAction(e -> sendMessage()); + VBox root = new VBox(10, inputField, sendButton); Scene scene = new Scene(root, 400, 300); @@ -24,4 +34,12 @@ public void start(Stage primaryStage) { public static void main(String[] args) { launch(args); } + + private void sendMessage() { + String message = inputField.getText().trim(); + if (!message.isEmpty()) { + chatArea.appendText("Вы: " + message + "\n"); + inputField.clear(); + } + } } From 2a61f8f0a7176111936f2f58a756701d6fc5d06b Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Thu, 20 Feb 2025 00:46:21 +0300 Subject: [PATCH 35/40] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81:=20=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BA=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ChatClientGUI.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Client/src/main/java/ru/project/ChatClientGUI.java b/Client/src/main/java/ru/project/ChatClientGUI.java index b6179a0..73fcd80 100644 --- a/Client/src/main/java/ru/project/ChatClientGUI.java +++ b/Client/src/main/java/ru/project/ChatClientGUI.java @@ -1,14 +1,22 @@ package ru.project; import javafx.application.Application; +import javafx.application.Platform; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.VBox; import javafx.stage.Stage; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.net.Socket; + public class ChatClientGUI extends Application { private TextArea chatArea; private TextField inputField; private Button sendButton; + private Socket socket; + private DataInputStream in; + private DataOutputStream out; @Override public void start(Stage primaryStage) { @@ -29,6 +37,8 @@ public void start(Stage primaryStage) { primaryStage.setTitle("Чат-клиент"); primaryStage.setScene(scene); primaryStage.show(); + + connectToServer(); } public static void main(String[] args) { @@ -42,4 +52,25 @@ private void sendMessage() { inputField.clear(); } } + private void connectToServer() { + try { + socket = new Socket("localhost", 8189); + in = new DataInputStream(socket.getInputStream()); + out = new DataOutputStream(socket.getOutputStream()); + chatArea.appendText("Подключено к серверу\n"); + + new Thread(() -> { + try { + while (true) { + String message = in.readUTF(); + Platform.runLater(() -> chatArea.appendText(message + "\n")); + } + } catch (Exception e) { + Platform.runLater(() -> chatArea.appendText(e.getMessage() + "\n")); + } + }).start(); + } catch (Exception e) { + chatArea.appendText(e.getMessage() + "\n"); + } + } } From 78fd5f6c760ee9a70e610877c546292f78a93c8a Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Thu, 20 Feb 2025 00:59:14 +0300 Subject: [PATCH 36/40] =?UTF-8?q?=D0=98=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D1=81?= =?UTF-8?q?=D0=BA=D0=BE=D0=B9=20=D1=87=D0=B0=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dataSources.xml | 12 +++++ .../main/java/ru/project/ChatClientGUI.java | 48 ++++++++++++++++--- .../ru/project/database/DatabaseManager.java | 2 +- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 2bfbbd0..409263e 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -14,5 +14,17 @@ $ProjectFileDir$ + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/postgres + + + + + + $ProjectFileDir$ + \ No newline at end of file diff --git a/Client/src/main/java/ru/project/ChatClientGUI.java b/Client/src/main/java/ru/project/ChatClientGUI.java index 73fcd80..a826c89 100644 --- a/Client/src/main/java/ru/project/ChatClientGUI.java +++ b/Client/src/main/java/ru/project/ChatClientGUI.java @@ -8,6 +8,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.IOException; import java.net.Socket; public class ChatClientGUI extends Application { @@ -17,6 +18,7 @@ public class ChatClientGUI extends Application { private Socket socket; private DataInputStream in; private DataOutputStream out; + private boolean isBanned = false; @Override public void start(Stage primaryStage) { @@ -24,11 +26,10 @@ public void start(Stage primaryStage) { chatArea.setEditable(false); chatArea.setWrapText(true); - TextField inputField = new TextField(); + inputField = new TextField(); inputField.setPromptText("Введите сообщение..."); Button sendButton = new Button("Отправить"); - sendButton.setOnAction(e -> sendMessage()); VBox root = new VBox(10, inputField, sendButton); @@ -47,9 +48,15 @@ public static void main(String[] args) { private void sendMessage() { String message = inputField.getText().trim(); - if (!message.isEmpty()) { - chatArea.appendText("Вы: " + message + "\n"); - inputField.clear(); + if (!message.isEmpty() && !isBanned) { + try { + out.writeUTF(message); // Отправляем на сервер + inputField.clear(); // Очищаем поле + } catch (IOException e) { + chatArea.appendText("Ошибка отправки сообщения\n"); + } + } else if (isBanned) { + chatArea.appendText("Вы не можете писать сообщения, так как заблокированы.\n"); } } private void connectToServer() { @@ -63,7 +70,7 @@ private void connectToServer() { try { while (true) { String message = in.readUTF(); - Platform.runLater(() -> chatArea.appendText(message + "\n")); + Platform.runLater(() -> processServerMessage(message)); } } catch (Exception e) { Platform.runLater(() -> chatArea.appendText(e.getMessage() + "\n")); @@ -73,4 +80,33 @@ private void connectToServer() { chatArea.appendText(e.getMessage() + "\n"); } } + private void processServerMessage(String message) { + if (message.startsWith("/")) { + if (message.equalsIgnoreCase("/exitok")) { + disconnect(); + } else if (message.startsWith("/authOK ")) { + chatArea.appendText("Авторизация успешна! Ваш ник: " + message.split(" ")[1] + "\n"); + } else if (message.startsWith("/regOK ")) { + chatArea.appendText("Регистрация успешна! Ваш ник: " + message.split(" ")[1] + "\n"); + } else if (message.equalsIgnoreCase("/banok")) { + isBanned = true; + chatArea.appendText("Вы были заблокированы администратором.\n"); + } else if (message.equalsIgnoreCase("/unbanok")) { + isBanned = false; + chatArea.appendText("Вы теперь разбанены и можете писать сообщения.\n"); + } + } else { + chatArea.appendText(message + "\n"); // Обычное сообщение + } + } + private void disconnect() { + try { + if (socket != null) socket.close(); + if (in != null) in.close(); + if (out != null) out.close(); + chatArea.appendText("Отключено от сервера\n"); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java index a9bb845..51ad55c 100644 --- a/Server/src/main/java/ru/project/database/DatabaseManager.java +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -4,7 +4,7 @@ import java.sql.*; public class DatabaseManager { - private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=postgres&password=postgres"; + private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=iakovlysenko&password=null"; public DatabaseManager() { From eb34b2d365da7ae15bbe4c0c17e101c69a168a3b Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Thu, 20 Feb 2025 01:07:02 +0300 Subject: [PATCH 37/40] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D1=87=D0=B0=D1=81=D1=82=D0=B8:=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D1=8C=20=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=B4=D0=B5=D1=82=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=BE=20=D0=B2=D0=B8=D0=B4=D0=B8=D1=82=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=20=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/src/main/java/ru/project/Server.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 40a4f29..d490365 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -42,11 +42,14 @@ public void start(){ public void subscribe(ClientHandler clientHandler){ clients.add(clientHandler); + broadcastMessage("В чат зашел: " + clientHandler.getUsername()); + System.out.println("[SERVER] Пользователь " + clientHandler.getUsername() + " подключился."); } public void unsubscribe(ClientHandler clientHandler){ clients.remove(clientHandler); broadcastMessage("Из чата вышел: "+ clientHandler.getUsername()); + System.out.println("[SERVER] Клиент " + clientHandler.getUsername() + " отключён."); } public void broadcastMessage(String message){ From da16f534785d98c0106128c1534c1ae673b0fd17 Mon Sep 17 00:00:00 2001 From: iakovlysenko Date: Thu, 20 Feb 2025 01:17:13 +0300 Subject: [PATCH 38/40] =?UTF-8?q?=D0=A0=D0=B0=D0=B1=D0=BE=D1=87=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/src/main/java/ru/project/ChatClientGUI.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Client/src/main/java/ru/project/ChatClientGUI.java b/Client/src/main/java/ru/project/ChatClientGUI.java index a826c89..37d5a53 100644 --- a/Client/src/main/java/ru/project/ChatClientGUI.java +++ b/Client/src/main/java/ru/project/ChatClientGUI.java @@ -2,10 +2,12 @@ import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Scene; -import javafx.scene.control.*; +import javafx.scene.control.Button; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; import javafx.scene.layout.VBox; import javafx.stage.Stage; - +import javafx.geometry.Insets; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -32,7 +34,8 @@ public void start(Stage primaryStage) { Button sendButton = new Button("Отправить"); sendButton.setOnAction(e -> sendMessage()); - VBox root = new VBox(10, inputField, sendButton); + VBox root = new VBox(10,chatArea, inputField, sendButton); + root.setPadding(new Insets(10, 10, 10, 10)); Scene scene = new Scene(root, 400, 300); primaryStage.setTitle("Чат-клиент"); From 949980bfc23541a700d28b5fa1e42a03327ce8bf Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sat, 22 Feb 2025 15:23:33 +0300 Subject: [PATCH 39/40] =?UTF-8?q?=D0=92=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BC=D0=BD=D0=B0=D1=82?= =?UTF-8?q?=D1=8B=20=D0=B8=20=D0=BF=D1=80=D0=B8=D1=81=D0=BE=D0=B5=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD=D1=8F=D1=82=D1=8C=D1=81=D1=8F=20=D0=BA=20=D0=BD?= =?UTF-8?q?=D0=B8=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/ru/project/ClientHandler.java | 20 +++++- Server/src/main/java/ru/project/Server.java | 24 ++++++- .../ru/project/database/DatabaseManager.java | 2 +- .../src/main/java/ru/project/rooms/Rooms.java | 62 +++++++++++++++++++ 4 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 Server/src/main/java/ru/project/rooms/Rooms.java diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index cdcb595..9fd354a 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -16,6 +16,7 @@ public class ClientHandler { private String username; private Role role; private long lastActiveTime; + private String currentRoom = null; public ClientHandler(Socket socket, Server server) throws IOException { this.socket = socket; @@ -125,9 +126,18 @@ public ClientHandler(Socket socket, Server server) throws IOException { } else sendMsg("Пользователь " + tokens[1] + " не находится в бане"); } else if (message.equalsIgnoreCase("/online")) { sendMsg(server.getOnlineUsers()); + } else if (message.startsWith("/createroom ")) { + String roomName = message.substring(12).trim(); + server.createRoom(roomName, this); + } else if (message.startsWith("/room ")) { + String roomName = message.substring(6).trim(); + server.joinRoom(roomName, this); + } else if (message.equals("/exitroom")) { + server.exitRoom(this); } - } - else { + } else if (currentRoom != null) { + server.sendToRoom(currentRoom, "[" + getCurrentTime() + "] " + username + ": " + message); + } else { String messageWithTime = "[" + getCurrentTime() + "]" + username + " : " + message; server.broadcastMessage(messageWithTime); } @@ -193,4 +203,10 @@ private String getCurrentTime() { public long getLastActiveTime() { return lastActiveTime; } + public void setCurrentRoom(String roomName) { + this.currentRoom = roomName; + } + public String getCurrentRoom() { + return currentRoom; + } } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index d490365..1aba609 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -2,12 +2,11 @@ import ru.project.checktime.CheckTime; import ru.project.database.DatabaseManager; +import ru.project.rooms.Rooms; -import javax.xml.crypto.Data; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -16,6 +15,7 @@ public class Server { private List clients; private Authenticator authenticator; private final DatabaseManager databaseManager; + private final Rooms rooms = new Rooms(); public Server(int port, DatabaseManager databaseManager) { this.port = port; @@ -25,7 +25,6 @@ public Server(int port, DatabaseManager databaseManager) { new CheckTime(this).start(); } - public void start(){ try (ServerSocket serverSocket = new ServerSocket(port)) { System.out.println("Сервер запущен на порту: " + port); @@ -134,4 +133,23 @@ public String getOnlineUsers() { public List getClients() { return this.clients; } + public void createRoom(String roomName, ClientHandler owner) { + rooms.createRoom(roomName, owner); + } + + public void joinRoom(String roomName, ClientHandler client) { + rooms.joinRoom(roomName, client); + } + + public void exitRoom(ClientHandler client) { + rooms.exitRoom(client); + } + + public void sendToRoom(String roomName, String message) { + rooms.sendToRoom(roomName, message); + } + + public boolean isUserInRoom(ClientHandler client) { + return rooms.isUserInRoom(client); + } } diff --git a/Server/src/main/java/ru/project/database/DatabaseManager.java b/Server/src/main/java/ru/project/database/DatabaseManager.java index 51ad55c..cdc8cac 100644 --- a/Server/src/main/java/ru/project/database/DatabaseManager.java +++ b/Server/src/main/java/ru/project/database/DatabaseManager.java @@ -4,7 +4,7 @@ import java.sql.*; public class DatabaseManager { - private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=iakovlysenko&password=null"; + private static final String DB_URL = "jdbc:postgresql://localhost:5432/postgres?currentSchema=public&user=admin&password=admin"; public DatabaseManager() { diff --git a/Server/src/main/java/ru/project/rooms/Rooms.java b/Server/src/main/java/ru/project/rooms/Rooms.java new file mode 100644 index 0000000..bcd8a5b --- /dev/null +++ b/Server/src/main/java/ru/project/rooms/Rooms.java @@ -0,0 +1,62 @@ +package ru.project.rooms; + +import ru.project.ClientHandler; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +public class Rooms { + private final Map> rooms = new ConcurrentHashMap<>(); + + public void createRoom(String roomName, ClientHandler owner) { + if (rooms.containsKey(roomName)) { + owner.sendMsg("Комната с таким именем уже существует."); + return; + } + if (owner.getCurrentRoom() != null) { + owner.sendMsg("Вы уже создали комнату: " + owner.getCurrentRoom()); + return; + } + rooms.put(roomName, new CopyOnWriteArrayList<>(List.of(owner))); + owner.setCurrentRoom(roomName); + owner.sendMsg("Вы создали комнату: " + roomName); + } + + public void joinRoom(String roomName, ClientHandler client) { + if (!rooms.containsKey(roomName)) { + client.sendMsg("Комната " + roomName + " не существует."); + return; + } + if (client.getCurrentRoom() != null) { + client.sendMsg("Вы уже находитесь в комнате: " + client.getCurrentRoom()); + return; + } + rooms.get(roomName).add(client); + client.setCurrentRoom(roomName); + sendToRoom(roomName, client.getUsername() + " присоединился к комнате."); + } + + public void exitRoom(ClientHandler client) { + String roomName = client.getCurrentRoom(); + if (roomName == null) { + client.sendMsg("Вы не находитесь в комнате."); + return; + } + rooms.get(roomName).remove(client); + client.setCurrentRoom(null); + sendToRoom(roomName, client.getUsername() + " покинул комнату."); + client.sendMsg("Вы вышли из комнаты."); + } + public void sendToRoom(String roomName, String message) { + if (!rooms.containsKey(roomName)) return; + for (ClientHandler client : rooms.get(roomName)) { + client.sendMsg(message); + } + } + + public boolean isUserInRoom(ClientHandler client) { + return client.getCurrentRoom() != null; + } +} From ceac01fca30a90864b4f61137b30ac10921fd3e4 Mon Sep 17 00:00:00 2001 From: Iakov Lysenko Date: Sat, 22 Feb 2025 15:58:27 +0300 Subject: [PATCH 40/40] =?UTF-8?q?=D0=A0=D0=B5=D0=BB=D0=B8=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D1=8F=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/inspectionProfiles/Project_Default.xml | 6 ++++++ .../main/java/ru/project/ClientHandler.java | 19 ++++++++++--------- Server/src/main/java/ru/project/Server.java | 18 ++++++++++++++---- .../java/ru/project/checktime/CheckTime.java | 7 ++----- .../ru/project/inMemoryAuthenticator.java | 13 ++++++------- 5 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..601f39c --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/Server/src/main/java/ru/project/ClientHandler.java b/Server/src/main/java/ru/project/ClientHandler.java index 9fd354a..c15ac90 100644 --- a/Server/src/main/java/ru/project/ClientHandler.java +++ b/Server/src/main/java/ru/project/ClientHandler.java @@ -15,8 +15,9 @@ public class ClientHandler { private final DataOutputStream out; private String username; private Role role; - private long lastActiveTime; + private final long lastActiveTime; private String currentRoom = null; + boolean banFlag; public ClientHandler(Socket socket, Server server) throws IOException { this.socket = socket; @@ -85,7 +86,7 @@ public ClientHandler(Socket socket, Server server) throws IOException { //Цикл работы while (true) { String message = in.readUTF(); - boolean targetUserIsBanned = false; + this.banFlag = false; if (message.startsWith("/")) { if (message.equalsIgnoreCase("/exit")) { sendMsg("/exitok"); @@ -113,17 +114,13 @@ public ClientHandler(Socket socket, Server server) throws IOException { continue; } server.banUser(tokens[1], this); - targetUserIsBanned = true; } else if (message.startsWith("/unban ")) { String[] tokens = message.split(" ", 2); if (tokens.length != 2) { sendMsg("Неверный формат комманды /unban"); continue; } - if (targetUserIsBanned) { - server.unbanUser(tokens[1], this); - targetUserIsBanned = false; - } else sendMsg("Пользователь " + tokens[1] + " не находится в бане"); + server.unbanUser(tokens[1], this); } else if (message.equalsIgnoreCase("/online")) { sendMsg(server.getOnlineUsers()); } else if (message.startsWith("/createroom ")) { @@ -186,7 +183,6 @@ public void disconnect() { public String getUsername() { return username; } - public void setUsername(String username) { this.username = username; } @@ -199,7 +195,6 @@ public Role getRole() { private String getCurrentTime() { return new SimpleDateFormat("HH:mm:ss").format(new Date()); } - public long getLastActiveTime() { return lastActiveTime; } @@ -209,4 +204,10 @@ public void setCurrentRoom(String roomName) { public String getCurrentRoom() { return currentRoom; } + public boolean isBanned() { + return banFlag; + } + public void changeBanFlag() { + banFlag = !banFlag; + } } diff --git a/Server/src/main/java/ru/project/Server.java b/Server/src/main/java/ru/project/Server.java index 1aba609..29c4a6e 100644 --- a/Server/src/main/java/ru/project/Server.java +++ b/Server/src/main/java/ru/project/Server.java @@ -95,8 +95,13 @@ public void banUser(String usernameToBan, ClientHandler adminHandler) { if (adminHandler.getRole().equals(Role.ADMIN)) { for (ClientHandler client : clients) { if (client.getUsername().equals(usernameToBan)) { - client.sendMsg("/banok"); - broadcastMessage("Пользователь " + usernameToBan + " был забанен администратором"); + if (client.isBanned()) { + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToBan + " уже забанен!"); + } else { + client.sendMsg("/banok"); + broadcastMessage("Пользователь " + usernameToBan + " был забанен администратором"); + client.changeBanFlag(); + } return; } } @@ -109,8 +114,13 @@ public void unbanUser(String usernameToUnban, ClientHandler adminHandler) { if (adminHandler.getRole().equals(Role.ADMIN)) { for (ClientHandler client : clients) { if (client.getUsername().equals(usernameToUnban)) { - client.sendMsg("/unbanok"); - broadcastMessage("Пользователь " + usernameToUnban + " был разбанен администратором"); + if (!client.isBanned()) { + adminHandler.sendMsg("Ошибка. Пользователь с ником " + usernameToUnban + " не находится в бане"); + } else { + client.sendMsg("/unbanok"); + broadcastMessage("Пользователь " + usernameToUnban + " был разбанен администратором"); + client.changeBanFlag(); + } return; } } diff --git a/Server/src/main/java/ru/project/checktime/CheckTime.java b/Server/src/main/java/ru/project/checktime/CheckTime.java index 3af8b5c..60aad48 100644 --- a/Server/src/main/java/ru/project/checktime/CheckTime.java +++ b/Server/src/main/java/ru/project/checktime/CheckTime.java @@ -2,12 +2,9 @@ import ru.project.*; -import java.util.ArrayList; - public class CheckTime extends Thread { private static final long TIMEOUT = 20 * 60 * 1000; - private Server server; - private ClientHandler clientHandler; + private final Server server; public CheckTime(Server server) { this.server = server; @@ -28,7 +25,7 @@ public void run() { } } } catch (InterruptedException e) { - e.printStackTrace(); + server.broadcastMessage("Ошибка CheckTime"); } } } diff --git a/Server/src/main/java/ru/project/inMemoryAuthenticator.java b/Server/src/main/java/ru/project/inMemoryAuthenticator.java index 18b8012..bd3a72e 100644 --- a/Server/src/main/java/ru/project/inMemoryAuthenticator.java +++ b/Server/src/main/java/ru/project/inMemoryAuthenticator.java @@ -1,14 +1,13 @@ package ru.project; -import java.util.Arrays; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class inMemoryAuthenticator implements Authenticator { - public class User { - private String username; - private String login; - private String password; + public static class User { + private final String username; + private final String login; + private final String password; public User(String username, String login, String password) { this.username = username; @@ -16,8 +15,8 @@ public User(String username, String login, String password) { this.password = password; } } - private List users; - private Server server; + private final List users; + private final Server server; public inMemoryAuthenticator(Server server) { users = new CopyOnWriteArrayList<>(); this.server = server;