From 00d39d73bc15cacd0b48cae9ab9ed63cbf59ca00 Mon Sep 17 00:00:00 2001 From: igor Date: Mon, 7 Apr 2025 07:47:59 +0500 Subject: [PATCH] + --- .../java/org/ccalm/jwt/MainController.java | 150 ++++++++++++++++++ .../java/org/ccalm/jwt/SecurityConfig.java | 1 + .../ccalm/jwt/models/VerificationModel.java | 20 +++ 3 files changed, 171 insertions(+) create mode 100644 src/main/java/org/ccalm/jwt/models/VerificationModel.java diff --git a/src/main/java/org/ccalm/jwt/MainController.java b/src/main/java/org/ccalm/jwt/MainController.java index 88abb6f..f367e77 100644 --- a/src/main/java/org/ccalm/jwt/MainController.java +++ b/src/main/java/org/ccalm/jwt/MainController.java @@ -611,6 +611,156 @@ public class MainController implements ServletContextAware { return json.toString(); } //------------------------------------------------------------------------------------------------------------------ + @Operation( + summary = "Verify CAPTCHA and send verification code to email", + description = "Before create a new user", + responses = { + @ApiResponse( + responseCode = "200", + description = "Successful response error_code = 0", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseModel.class) + ) + ), + @ApiResponse( + responseCode = "500", + description = "Internal server error", + content = @Content( + mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseModel.class) + ) + ) + } + ) + @Transactional + @RequestMapping(value = "/verification",method = {RequestMethod.POST,RequestMethod.GET},produces = "application/json;charset=utf-8") + @ResponseBody + public ResponseEntity verification( + @RequestBody VerificationModel verificationModel, + HttpServletResponse response, + HttpServletRequest request, + @CookieValue(value = "lng",defaultValue="1") String language_id + ) { + Translation trt = new Translation(language_id,jdbcTemplate); + try { + String signature1 = afterLast(verificationModel.getToken(), "."); + String payload = beforeFirst(verificationModel.getToken(), "."); + + String signature2 = Tools.generateSignature(captchaKey, payload); + if (!signature1.equals(signature2)) { + throw new CustomException(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(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(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(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(10000, trt.trt(false, "The_email_field_is_incorrect"),null,false); + } + if (!verificationModel.getEmail().equals(jToken.getString("email"))) { + throw new CustomException(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 +// String result=null; +// try(Cache cache = new Cache(redis_host,redis_port,redis_password)) { +// cache.open(); +// String data = cache.get(userDetails.getSignature()); +// if (data != null) { +// logout(response,request); +// if (data.equals("repeat")) { +// throw new CustomException(10000, Arrays.asList(trt.trt(false,"Please_log_in"), trt.trt(false,"Reauthorization_detected_if_it_is_not_you_please_change_your_password")), null, false); +// }else { +// throw new CustomException(10000, Arrays.asList(trt.trt(false,"Please_log_in"), trt.trt(false,"Your_authorization_token_is_not_valid")), null, false); +// } +// } +// } + + int len=10; + StringBuilder sb = new StringBuilder(len); + SecureRandom secureRandom = new SecureRandom(); + for (int i = 0; i < len; i++) { + sb.append(secureRandom.nextInt(10)); // 0–9 + } + String code = sb.toString(); + + String sql; + //Проверяю не несколько ли раз нажал кнопку отправить... + sql= """ + select * from users.verification where email=:email and captcha=:captcha + """; + MapSqlParameterSource parameters = new MapSqlParameterSource(); + parameters.addValue("email", verificationModel.getEmail()); + parameters.addValue("captcha", verificationModel.getCode()); + List ret = jdbcTemplate.query(sql, parameters, new DBTools.JsonRowMapper()); + for (int i = 0; i < ret.size(); i++) { + throw new CustomException(10000, trt.trt(false, "Please_update_the_captcha_and_resubmit_it"),null,false); + } + //Delete previous verification records + sql= """ + delete from users.verification where email=LOWER(TRIM(:email)) + """; + parameters = new MapSqlParameterSource(); + parameters.addValue("email", verificationModel.getEmail()); + jdbcTemplate.update(sql, parameters); + //Insert new verification code + sql= """ + insert into users.verification( + email, + code, + captcha + )values( + :email, + :code, + :captcha + ) + """; + parameters = new MapSqlParameterSource(); + parameters.addValue("email", verificationModel.getEmail()); + parameters.addValue("code", code); + parameters.addValue("captcha", verificationModel.getCode()); + jdbcTemplate.update(sql, parameters); + + + //Sending verification code to email + String html=""; + html += "" + trt.trt(true,"Code") + ""; + html += "

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

"; + html += trt.trt(true, "Code") + ": " + code + ""; + html += ""; + + try { + EmailUtility.sendEmail(mail_host, mail_port, mail_login, mail_password, verificationModel.getEmail(), trt.trt(true,"Email_verification_code"), html); + } catch (MessagingException e) { + throw new CustomException(10000, String.format(trt.trt(false, "Failed_send_mail_to_s"), verificationModel.getEmail()),null,false); + } + + return new ResponseEntity<>(new ErrorResponseModel(0,trt.trt(false, "The_verification_code_has_been_sent_to_your_email_address"),null), HttpStatus.OK); + } catch (CustomException e) { + return new ResponseEntity<>(e.getErrorResponseModel(), HttpStatus.OK); + } catch (Exception e) { + String uuid = UUID.randomUUID().toString(); + logger.error(uuid, e); + return new ResponseEntity<>(new ErrorResponseModel(10000, trt.trt(false,"Internal_Server_Error"), null, uuid), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + //------------------------------------------------------------------------------------------------------------------ @Transactional @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") diff --git a/src/main/java/org/ccalm/jwt/SecurityConfig.java b/src/main/java/org/ccalm/jwt/SecurityConfig.java index 57d4e38..16cc4ed 100644 --- a/src/main/java/org/ccalm/jwt/SecurityConfig.java +++ b/src/main/java/org/ccalm/jwt/SecurityConfig.java @@ -60,6 +60,7 @@ public class SecurityConfig { path.equals("/reset") || path.equals("/get_session") || path.equals("/get_request_token") || + path.equals("/verification") || path.equals("/access"); } diff --git a/src/main/java/org/ccalm/jwt/models/VerificationModel.java b/src/main/java/org/ccalm/jwt/models/VerificationModel.java new file mode 100644 index 0000000..d2ff7a1 --- /dev/null +++ b/src/main/java/org/ccalm/jwt/models/VerificationModel.java @@ -0,0 +1,20 @@ +package org.ccalm.jwt.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class VerificationModel { + @JsonProperty("email") + private String email; + @JsonProperty("code") + private String code; + @JsonProperty("token") + private String token; +}