diff --git a/pom.xml b/pom.xml index 1c54268..8940af0 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ org.ccalm jwt - 0.0.1-SNAPSHOT + 1.0.1 jwt jwt @@ -79,16 +79,7 @@ json 20231013 - - + io.jsonwebtoken jjwt-api @@ -180,6 +171,7 @@ + org-ccalm-jwt org.springframework.boot diff --git a/src/main/java/org/ccalm/jwt/MainController.java b/src/main/java/org/ccalm/jwt/MainController.java index bfd2405..a219b2e 100644 --- a/src/main/java/org/ccalm/jwt/MainController.java +++ b/src/main/java/org/ccalm/jwt/MainController.java @@ -204,6 +204,23 @@ public class MainController implements ServletContextAware { return ""; } //------------------------------------------------------------------------------------------------------------------ + public static void validatePassword(String password) throws CustomException { + Translation trt = new Translation("en",null); + + if(password.isEmpty()) + throw new CustomException(200, 10000,trt.trt(false,"The_password_field_is_empty"),null,false); + if(!Pattern.compile("[0-9]").matcher(password).find()) + throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_number"),null,false); + if(!Pattern.compile("[a-z]").matcher(password).find()) + throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_small_Latin_letter"),null,false); + if (!Pattern.compile("[A-Z]").matcher(password).find()) + throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_big_Latin_letter"),null,false); + if (!Pattern.compile("[_!@#$%^&*]").matcher(password).find()) + throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_special_letter"),null,false); + if (password.length() < 6) + throw new CustomException(200, 10000,trt.trt(false,"The_password_is_less_than_six_characters"),null,false); + } + //------------------------------------------------------------------------------------------------------------------ private PrivateKey getPrivateKey() { try { byte[] keyBytes = Base64.getDecoder().decode(this.private_key); @@ -343,20 +360,20 @@ public class MainController implements ServletContextAware { json.put("error_message",""); json.put("error_marker",(String)null); String buildDate=""; - //String buildVersion=""; + String buildVersion=""; try { InputStream inputStream = MainController.class.getClassLoader().getResourceAsStream("META-INF/build-info.properties"); if (inputStream != null) { Properties properties = new Properties(); properties.load(inputStream); buildDate = properties.getProperty("build.time"); - //buildVersion = properties.getProperty("build.version"); + buildVersion = properties.getProperty("build.version"); } } catch (Exception e) { e.printStackTrace(); } json.put("build_date",buildDate); - //json.put("build_version",buildVersion); + json.put("version",buildVersion); json.put("name",application_name); //json.put("active_connections",dataSource.getHikariPoolMXBean().getActiveConnections()); //json.put("idle_connections",dataSource.getHikariPoolMXBean().getIdleConnections()); @@ -597,7 +614,7 @@ public class MainController implements ServletContextAware { byte[] bytes = baos.toByteArray(); json.put("image",Base64.getEncoder().encodeToString(bytes)); } catch (IOException e) { - throw new CustomException(401, 10000, trt.trt(false, "Input_output_error"),UUID.randomUUID().toString(),true); + throw new CustomException(500, 10000, trt.trt(false, "Input_output_error"),UUID.randomUUID().toString(),true); } //Формирую JSON токена и шифрую его @@ -674,19 +691,19 @@ public class MainController implements ServletContextAware { } if(jToken==null) { - throw new CustomException(401, 10000, trt.trt(false, "Please_send_a_valid_JSON_string_in_your_token"),null,false); + throw new CustomException(200, 10000, trt.trt(false, "Please_send_a_valid_JSON_string_in_your_token"),null,false); } if (!verificationModel.getCode().equals(jToken.getString("code"))) { - throw new CustomException(401, 10000, trt.trt(false, "The_code_did_not_match_what_was_specified_in_the_captcha"),null,false); + throw new CustomException(200, 10000, trt.trt(false, "The_code_did_not_match_what_was_specified_in_the_captcha"),null,false); } if (jToken.getLong("exp") < (System.currentTimeMillis() / 1000L)) { - throw new CustomException(401, 10000, List.of(trt.trt(false, "Captcha_is_outdated"),trt.trt(false, "Please_update_the_captcha")),null,false); + throw new CustomException(200, 10000, List.of(trt.trt(false, "Captcha_is_outdated"),trt.trt(false, "Please_update_the_captcha")),null,false); } if (!Tools.isValidEmail(jToken.getString("email"))) { - throw new CustomException(401, 10000, trt.trt(false, "The_email_field_is_incorrect"),null,false); + throw new CustomException(200, 10000, trt.trt(false, "The_email_field_is_incorrect"),null,false); } if (!verificationModel.getEmail().equals(jToken.getString("email"))) { - throw new CustomException(401, 10000, trt.trt(false, "The_email_did_not_match_what_was_specified_in_the_captcha"),null,false); + throw new CustomException(200, 10000, trt.trt(false, "The_email_did_not_match_what_was_specified_in_the_captcha"),null,false); } //If this is a repeat authorization, then we inform the client about it @@ -780,7 +797,10 @@ public class MainController implements ServletContextAware { @Operation(summary = "Create new user account", description = "After creating a user, adding a default user role") @RequestMapping(value = "/create",method = RequestMethod.POST,produces = "application/json;charset=utf-8") @ResponseBody - public ResponseEntity create(@RequestBody NewUserModel newUserModel,@RequestParam(required=false,name="lng",defaultValue="1") String language_id) { + public ResponseEntity create( + @RequestBody NewUserModel newUserModel, + @RequestParam(required=false,name="lng",defaultValue="1") String language_id + ) { Translation trt = new Translation(language_id,jdbcTemplate); try{ JSONObject json = new JSONObject(); @@ -796,65 +816,41 @@ public class MainController implements ServletContextAware { if (!Tools.isValidEmail(newUserModel.getEmail())) { throw new CustomException(400, 10000, trt.trt(false, "The_email_field_is_incorrect"),null,false); } - if(newUserModel.getCode().length()<3) { + if(newUserModel.getCode().isEmpty()) { throw new CustomException(400, 10000, trt.trt(false, "The_code_field_is_empty"),null,false); } - if(newUserModel.getToken().length()<3) { - throw new CustomException(400, 10000, trt.trt(false, "The_token_field_is_empty"),null,false); - } + //if(newUserModel.getToken().length()<3) { + // throw new CustomException(400, 10000, trt.trt(false, "The_token_field_is_empty"),null,false); + //} + validatePassword(newUserModel.getPassword()); - //Проверяю что подпись одинакова - String signature1 = afterLast(newUserModel.getToken(), "."); - String payload = beforeFirst(newUserModel.getToken(), "."); - - String signature2 = Tools.generateSignature(captchaKey, payload); - if (!signature1.equals(signature2)) { - throw new CustomException(400, 10000, trt.trt(false, "The_signature_did_not_match"),null,false); - } - //Расшифровываю - String sToken = Tools.decryptText(captchaKey,payload); - - JSONObject jToken = null; - try { - jToken = new JSONObject(sToken); - } catch (JSONException e) { - logger.error(e); - } - - if(jToken==null) { - throw new CustomException(400, 10000, trt.trt(false, "Please_send_a_valid_JSON_string_in_your_token"),null,false); - } - if (!newUserModel.getCode().equals(jToken.getString("code"))) { - throw new CustomException(400, 10000, trt.trt(false, "The_code_did_not_match_what_was_specified_in_the_captcha"),null,false); - } - if (jToken.getLong("exp") < (System.currentTimeMillis() / 1000L)) { - throw new CustomException(400, 10000, List.of(trt.trt(false, "Captcha_is_outdated"),trt.trt(false, "Please_update_the_captcha")),null,false); - } - if (!Tools.isValidEmail(jToken.getString("email"))) { - throw new CustomException(400, 10000, trt.trt(false, "The_email_field_is_incorrect"),null,false); - } - if (!newUserModel.getEmail().equals(jToken.getString("email"))) { - throw new CustomException(400, 10000, trt.trt(false, "The_email_did_not_match_what_was_specified_in_the_captcha"),null,false); - } - - //Проверяю существование пользователя с таким email - String sql = """ - select * from main._users where email=:email; - """; + //We check that the verification code is equal to the one sent to the email + boolean existCode=false; + String sql= """ + select * from users.verification where email=:email and code=:code + """; MapSqlParameterSource parameters = new MapSqlParameterSource(); parameters.addValue("email", newUserModel.getEmail()); + parameters.addValue("code", newUserModel.getCode()); List ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); + for (int i = 0; i < ret.size(); i++) { + existCode = true; + } + if(!existCode){ + throw new CustomException(400, 10000, trt.trt(false, "The_email_verification_code_does_not_match_the_expected_code"),null,false); + } + + //Check if a user with this email exists + sql = """ + select * from main._users where email=:email; + """; + parameters = new MapSqlParameterSource(); + parameters.addValue("email", newUserModel.getEmail()); + ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); for (int i = 0; i < ret.size(); i++) { throw new CustomException(200, 10000, trt.trt(false, "A_user_with_the_same_email_address_already_exists"),null,false); } - // Генерируем временный пароль - RandomStringGenerator generator = new RandomStringGenerator.Builder() - .withinRange('0', 'z') // диапазон символов (можно настроить) - .filteredBy(c -> Character.isLetterOrDigit(c)) - .get(); - String password = generator.generate(8); - //Добавляем пользователя sql = """ insert into main._users( @@ -878,7 +874,7 @@ public class MainController implements ServletContextAware { pgp_sym_encrypt(CAST(:e_phone AS TEXT), CAST(:key AS TEXT)), :email, crypt(:password, gen_salt('bf')), - now()+interval '5 day' + now()+interval '365 day' ) RETURNING id; """; parameters = new MapSqlParameterSource(); @@ -891,7 +887,7 @@ public class MainController implements ServletContextAware { parameters.addValue("e_phone",newUserModel.getPhone(), Types.VARCHAR); parameters.addValue("email",newUserModel.getEmail(), Types.VARCHAR); parameters.addValue("key",personal_data_key, Types.VARCHAR); - parameters.addValue("password",password, Types.VARCHAR); + parameters.addValue("password",newUserModel.getPassword(), Types.VARCHAR); ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); for (int i = 0; i < ret.size(); i++) { @@ -909,8 +905,8 @@ public class MainController implements ServletContextAware { String html=""; html += "" + trt.trt(true,"Now_user") + ""; html += "

" + trt.trt(true, "To_activate_the_user_please_log_in") + ":

"; - html += "istransit.kz

"; - html += trt.trt(true, "To_log_in_please_use_the_following_password") + ": \"" + password + "\""; + html += ""+url_main+"

"; + html += trt.trt(true, "To_log_in_please_use_the_following_password") + ": \"" + newUserModel.getPassword() + "\""; html += ""; try { @@ -1032,39 +1028,6 @@ public class MainController implements ServletContextAware { int attempt_limit = bResult.get("attempt_limit"); //attempt_duration=0; - /*String sql = ""; - int attempt_count=0, attempt_limit=0, attempt_duration=0; - MapSqlParameterSource parameters = null; - List ret = null; - try { - sql = "select * from main.user_is_blocked(:login,:ip)"; - parameters = new MapSqlParameterSource(); - parameters.addValue("login", loginModel.getLogin()); - parameters.addValue("ip", ipAddress); - ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); - for (int i = 0; i < ret.size(); i++) { - json = new JSONObject(ret.get(i)); - if (!json.has("result") || json.getBoolean("result")) { - if(json.getInt("count")==0) - { - throw new CustomException(200, 10000, trt.trt(false, "The_user_account_is_blocked"),null,false); - }else{ - throw new CustomException(200, 10000, trt.trt(false, "The_limit_of_authorization_attempts_has_been_exceeded_please_wait_s_minutes"), String.valueOf(json.getInt("limit_duration")),(String)null,false); - } - } - if(json.has("count") && json.has("limit_count") && json.has("limit_duration")) { - attempt_count = json.getInt("count") + 1; - attempt_limit = json.getInt("limit_count"); - //attempt_duration = json.getInt("limit_duration"); - } - } - }catch (DataAccessException ex){ - String uuid = UUID.randomUUID().toString(); - logger.error("Функция main.user_is_blocked не вернула результата!", uuid, ex); - throw new CustomException(500, 10000, trt.trt(false, "Error_executing_SQL_query"),uuid,false); - }*/ - - MapSqlParameterSource parameters = null; String sql = ""; List ret = null; @@ -1262,7 +1225,6 @@ public class MainController implements ServletContextAware { //json.put("error_marker",(String)null); json.put("ip",ipAddress); - String rolesString = json.getJSONObject("roles").getString("value"); JSONArray rolesArray = new JSONArray(rolesString); json.put("roles",rolesArray); @@ -1298,7 +1260,7 @@ public class MainController implements ServletContextAware { { throw new CustomException(200, 10000, trt.trt(false, "The_user_account_is_blocked"),null,false); }else{ - throw new CustomException(200, 10000, java.lang.String.format(trt.trt(false, "The_limit_of_authorization_attempts_has_been_exceeded_please_wait_s_minutes"), json.getInt("limit_duration")),null,false); + throw new CustomException(200, 10000, List.of(trt.trt(false, "The_limit_of_authorization_attempts_has_been_exceeded_please_wait_s_minutes")), List.of(String.valueOf(json.getInt("limit_duration"))),"",false); } } if(json.has("count") && json.has("limit_count") && json.has("limit_duration")) { @@ -1307,6 +1269,8 @@ public class MainController implements ServletContextAware { //attempt_duration = json.getInt("limit_duration"); } } + } catch (CustomException e) { + throw e; }catch (DataAccessException ex){ java.lang.String uuid = UUID.randomUUID().toString(); logger.error(uuid, ex); @@ -1355,38 +1319,6 @@ public class MainController implements ServletContextAware { int attempt_limit = bResult.get("attempt_limit"); //attempt_duration=0; - /*String sql = ""; - int attempt_count=0, attempt_limit=0, attempt_duration=0; - MapSqlParameterSource parameters = null; - List ret = null; - try { - sql = "select * from main.user_is_blocked(:login,:ip)"; - parameters = new MapSqlParameterSource(); - parameters.addValue("login", loginModel.getLogin()); - parameters.addValue("ip", ipAddress); - ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); - for (int i = 0; i < ret.size(); i++) { - json = new JSONObject(ret.get(i)); - if (!json.has("result") || json.getBoolean("result")) { - if(json.getInt("count")==0) - { - throw new CustomException(200, 10000, trt.trt(false, "The_user_account_is_blocked"),null,false); - }else{ - throw new CustomException(200, 10000, trt.trt(false, "The_limit_of_authorization_attempts_has_been_exceeded_please_wait_s_minutes"), String.valueOf(json.getInt("limit_duration")),(String)null,false); - } - } - if(json.has("count") && json.has("limit_count") && json.has("limit_duration")) { - attempt_count = json.getInt("count"); - attempt_limit = json.getInt("limit_count"); - //attempt_duration = json.getInt("limit_duration"); - } - } - }catch (DataAccessException ex){ - String uuid = UUID.randomUUID().toString(); - logger.error("Error executing SQL query", uuid, ex); - throw new CustomException(200, 10000, trt.trt(false, "Error_executing_SQL_query"),uuid,false); - }*/ - String sql = ""; MapSqlParameterSource parameters = null; List ret = null; @@ -1754,8 +1686,11 @@ public class MainController implements ServletContextAware { //------------------------------------------------------------------------------------------------------------------ @RequestMapping(value = "/update",method = {RequestMethod.POST,RequestMethod.GET},produces = "application/json;charset=utf-8") @ResponseBody - public ResponseEntity update(HttpServletRequest request, @RequestBody UpdateModel update, @RequestParam(required=false,name="lng",defaultValue="1") String language_id) { - + public ResponseEntity update( + HttpServletRequest request, + @RequestBody UpdateModel update, + @RequestParam(required=false,name="lng",defaultValue="1") String language_id + ) { Translation trt = new Translation(language_id,jdbcTemplate); try { JSONObject json = new JSONObject(); @@ -1770,19 +1705,8 @@ public class MainController implements ServletContextAware { throw new CustomException(200, 10000, trt.trt(false,"The_email_field_is_incorrect"),null,false); if(update.getPassword().isEmpty()) throw new CustomException(200, 10000,trt.trt(false,"The_password_field_is_empty"),null,false); - if(update.getPasswordNew().isEmpty()) - throw new CustomException(200, 10000,trt.trt(false,"The_new_password_field_is_empty"),null,false); - if(!Pattern.compile("[0-9]").matcher(update.getPasswordNew()).find()) - throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_number"),null,false); - if(!Pattern.compile("[a-z]").matcher(update.getPasswordNew()).find()) - throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_small_Latin_letter"),null,false); - if (!Pattern.compile("[A-Z]").matcher(update.getPasswordNew()).find()) - throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_big_Latin_letter"),null,false); - if (!Pattern.compile("[_!@#$%^&*]").matcher(update.getPasswordNew()).find()) - throw new CustomException(200, 10000,trt.trt(false,"The_password_is_missing_a_special_letter"),null,false); - if (update.getPasswordNew().length() < 6) - throw new CustomException(200, 10000,trt.trt(false,"The_password_is_less_than_six_characters"),null,false); + validatePassword(update.getPasswordNew()); //Проверяем попытки смены пароля (сохраение попыток в функции логина) String ipAddress = request.getHeader("X-FORWARDED-FOR"); @@ -1795,24 +1719,6 @@ public class MainController implements ServletContextAware { int attempt_limit = bResult.get("attempt_limit"); //attempt_duration=0; - //String sql = "select main.user_is_blocked(:login,:ip) as block"; - /*String sql = "select * from main.user_is_blocked(:login,:ip)"; - MapSqlParameterSource parameters = new MapSqlParameterSource(); - parameters.addValue("login", update.getLogin()); - parameters.addValue("ip", ipAddress); - List ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); - JSONObject rows=null; - for (int i = 0; i < ret.size(); i++) { - rows = new JSONObject(ret.get(i)); - if(rows.getBoolean("result")) { - throw new CustomException(200, 10000, String.format(trt.trt(false,"The_limit_of_authorization_attempts_has_been_exceeded_please_wait_s_minutes"), 5),null, false); - } - } - if(rows==null) { - logger.error("Функция main.user_is_blocked не вернула результата!"); - throw new CustomException(200, 10000, trt.trt(false,"Error_executing_SQL_query"),null, false); - }*/ - //Получаю id пользователя TODO should work through the authorization function String sql = "select id from main._users where del=false and password=crypt(:password, password) and email=:email"; MapSqlParameterSource parameters = new MapSqlParameterSource(); @@ -1904,7 +1810,7 @@ public class MainController implements ServletContextAware { } } } - return new ResponseEntity<>(new ErrorResponseModel(200, 0), HttpStatus.OK); + return new ResponseEntity<>(new ErrorResponseModel(200, 0,"",""), HttpStatus.OK); } catch (CustomException e) { if(e.isSaveToLog()) { logger.error(e.getErrorMarker(), e); diff --git a/src/main/java/org/ccalm/jwt/models/NewUserModel.java b/src/main/java/org/ccalm/jwt/models/NewUserModel.java index d725c60..0f98aa9 100644 --- a/src/main/java/org/ccalm/jwt/models/NewUserModel.java +++ b/src/main/java/org/ccalm/jwt/models/NewUserModel.java @@ -31,6 +31,10 @@ public class NewUserModel { private String code; @JsonProperty("token") private String token; + + @JsonProperty("password") + private String password; + /* public String getCountry() { if(country==null) return "";