From d71fffd353f7b86e8e84d01a8754b40a5fa6d8f2 Mon Sep 17 00:00:00 2001 From: MathewFrancis Date: Mon, 25 Aug 2025 13:33:35 +0530 Subject: [PATCH] ApiResponse --- .../CezenABSAuthenticationProvider.java | 115 ++++++++++++ ...zenCustomAuthenticationProviderForBTC.java | 16 +- .../cezenBTC/controller/AbsController.java | 7 +- .../service/ABS/ABSServiceForLogIn.java | 174 ++++++++++++++++++ struct.txt | 0 5 files changed, 300 insertions(+), 12 deletions(-) create mode 100644 springHorse/src/main/java/com/example/cezenBTC/config/CezenABSAuthenticationProvider.java create mode 100644 struct.txt diff --git a/springHorse/src/main/java/com/example/cezenBTC/config/CezenABSAuthenticationProvider.java b/springHorse/src/main/java/com/example/cezenBTC/config/CezenABSAuthenticationProvider.java new file mode 100644 index 0000000..c9d37be --- /dev/null +++ b/springHorse/src/main/java/com/example/cezenBTC/config/CezenABSAuthenticationProvider.java @@ -0,0 +1,115 @@ +package com.example.cezenBTC.config; + +import com.example.cezenBTC.DAO.UserOpsDAO; +import com.example.cezenBTC.entity.user.UserEntity; +import com.example.cezenBTC.service.ABS.ABSServiceForLogIn; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class CezenABSAuthenticationProvider implements AuthenticationProvider/* */{ + + @Autowired + private UserOpsDAO userOpsDAO; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private ABSServiceForLogIn absServiceForLogIn; + + //@Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + + //get credentials from login form + String[] karthickHamu = authentication.getName().split(","); + String userStringId = karthickHamu[0]; + String btId = karthickHamu[1]; + String pwd = authentication.getCredentials().toString(); + + System.out.println("user Id " + userStringId + " password " + pwd); + + + //sanity check + if (userStringId.isEmpty() || pwd.isEmpty()) return null; + + // validate if the user input consists of only numbers + // and in the number rage is only 12 + try{ + if(userStringId.length() != 12){ + System.out.println("Number not equal to 12"); + return null; + } + Double.parseDouble(userStringId); + }catch (Exception e){ + System.out.println(e.toString()); + return null; + } + + + //check for employee + UserEntity user = null; + try { + //check if employee exists if yes then fetch details + user = this.userOpsDAO.getUserByUserStringId(userStringId); + } catch (Exception e) { + System.out.println(e.toString()); + return null; + } + + Object returnData = null; + +// for(int i =0; i < 5; i++){ +// +// if(returnData != null && returnData) +// +// } + + // this need to change for ABS + if (passwordEncoder.matches(pwd, user.getPassword())) { + + //then it is a match a number of springs granted authorities + List authorities = new ArrayList<>(); + + //loop through the users authorities and add each of them to simple granted authority + try { + //check if user is part of permission set for admin signing in + boolean isAdmin = false; + for(var permission : user.getRoles()){ + if(permission.getRole().equals("ROLE_admin")) isAdmin = true; + } + if(!isAdmin) throw new BadCredentialsException("no employee permission for given employee"); + + user.getRoles().forEach(a -> authorities.add(new SimpleGrantedAuthority(a.getRole()))); + } catch (Exception e) { + //use/**/r doesn't have permissions or roles = null + System.out.println(e.toString()); + return null; + } + System.out.println("Auth DONE"); + + return new UsernamePasswordAuthenticationToken(user.getUserIdNumber()+","+btId, pwd, authorities); + } else { + throw new BadCredentialsException("Invalid password!"); + } + } + + @Override + public boolean supports(Class authentication) { + //tells spring that i want to support username password style of auth + return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); + } +} + + diff --git a/springHorse/src/main/java/com/example/cezenBTC/config/CezenCustomAuthenticationProviderForBTC.java b/springHorse/src/main/java/com/example/cezenBTC/config/CezenCustomAuthenticationProviderForBTC.java index 36f02f0..04e49a7 100755 --- a/springHorse/src/main/java/com/example/cezenBTC/config/CezenCustomAuthenticationProviderForBTC.java +++ b/springHorse/src/main/java/com/example/cezenBTC/config/CezenCustomAuthenticationProviderForBTC.java @@ -17,7 +17,7 @@ import java.util.ArrayList; import java.util.List; @Component -public class CezenCustomAuthenticationProviderForBTC implements AuthenticationProvider { +public class CezenCustomAuthenticationProviderForBTC /*implements AuthenticationProvider */ { @Autowired private UserOpsDAO userOpsDAO; @@ -25,12 +25,12 @@ public class CezenCustomAuthenticationProviderForBTC implements AuthenticationPr @Autowired private PasswordEncoder passwordEncoder; - @Override + //@Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { //get credentials from login form String[] karthickHamu = authentication.getName().split(","); - String userStringId = karthickHamu[0]; + String userStringId = karthickHamu[0]+"disabled by ABS"; String btId = karthickHamu[1]; String pwd = authentication.getCredentials().toString(); @@ -92,10 +92,10 @@ public class CezenCustomAuthenticationProviderForBTC implements AuthenticationPr } } - @Override - public boolean supports(Class authentication) { - //tells spring that i want to support username password style of auth - return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); - } +// @Override +// public boolean supports(Class authentication) { +// //tells spring that i want to support username password style of auth +// return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); +// } } diff --git a/springHorse/src/main/java/com/example/cezenBTC/controller/AbsController.java b/springHorse/src/main/java/com/example/cezenBTC/controller/AbsController.java index 68815dc..7e0de45 100644 --- a/springHorse/src/main/java/com/example/cezenBTC/controller/AbsController.java +++ b/springHorse/src/main/java/com/example/cezenBTC/controller/AbsController.java @@ -1,11 +1,10 @@ package com.example.cezenBTC.controller; +import com.example.cezenBTC.DTO.CenteralServerConect.ApiResponse; import com.example.cezenBTC.absbridge.model.HealthResponse; import com.example.cezenBTC.absbridge.model.LoginRequest; -import com.example.cezenBTC.config.AbsClient; import com.example.cezenBTC.service.ABS.ABSServiceForLogIn; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; @@ -35,8 +34,8 @@ public class AbsController { } @PostMapping(value = "/login", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public Object login(@RequestBody LoginRequest req) { + public ApiResponse login(@RequestBody LoginRequest req) { - return absServiceForLogIn.loginRew(req); + return absServiceForLogIn.loginRewWithFixedResponse(req); } } \ No newline at end of file diff --git a/springHorse/src/main/java/com/example/cezenBTC/service/ABS/ABSServiceForLogIn.java b/springHorse/src/main/java/com/example/cezenBTC/service/ABS/ABSServiceForLogIn.java index 3b9ee7b..c2229fd 100644 --- a/springHorse/src/main/java/com/example/cezenBTC/service/ABS/ABSServiceForLogIn.java +++ b/springHorse/src/main/java/com/example/cezenBTC/service/ABS/ABSServiceForLogIn.java @@ -1,5 +1,9 @@ package com.example.cezenBTC.service.ABS; +import com.example.cezenBTC.DTO.CenteralServerConect.ApiResponse; +import com.example.cezenBTC.DTO.CenteralServerConect.Encryption; +import com.example.cezenBTC.DTO.CenteralServerConect.Log; +import com.example.cezenBTC.DTO.CenteralServerConect.RcvHeaderRaw; import com.example.cezenBTC.DTO.bridge.RcvHeader; import com.example.cezenBTC.DTO.bridge.RcvLog; import com.example.cezenBTC.absbridge.core.AbsProtocol; @@ -155,6 +159,7 @@ public class ABSServiceForLogIn { } } + json.put("offsetProbe", Map.of( "bodyOffset", bodyOffset, "around", new String(slice(reply, Math.max(0, bodyOffset - 8), @@ -177,6 +182,175 @@ public class ABSServiceForLogIn { } + public ApiResponse loginRewWithFixedResponse(LoginRequest req){ + + ApiResponse apiResponse = null; + + try { + if (isEmpty(req.opCard) || isEmpty(req.btId) || (isEmpty(req.password) && isEmpty(req.passwordEnc))) { + throw new Exception("One of the fields are empty"); + } + + String passwd; + Map encMeta = new LinkedHashMap<>(); + if (req.passwordEnc != null && !req.passwordEnc.isBlank()) { + passwd = req.passwordEnc; + encMeta.put("used", false); + encMeta.put("providedPasswordEnc", true); + } else { + AbsProtocol.Enc enc = AbsProtocol.encryptPasswordLikeMFC(req.password); + passwd = enc.enc(); + encMeta.put("used", true); + encMeta.put("utcSeconds", enc.utcSeconds()); + encMeta.put("key", enc.key()); + encMeta.put("encPasswd", passwd); + } + + int btMake = extractBtMake(req.btMake); + + byte[] sndHeader = AbsProtocol.packSndHeader( + AbsProtocol.LOG, AbsProtocol.LOGBT, 1, 1, 0, btMake + ); + byte[] sndLog = AbsProtocol.packSndLog( + safe(req.usrId), safe(req.opCard), passwd, safe(req.btId) + ); + + byte[] sendBuf = concat(sndHeader, sndLog); + byte[] reply = client.roundtrip(sendBuf, 10_000); + + byte[] hdrSlice = slice(reply, 0, Math.min(reply.length, 24)); + RcvHeader rcvHeader = AbsProtocol.parseRcvHeaderFlexible(hdrSlice); + + Map json = new LinkedHashMap<>(); + json.put("ok", true); + json.put("target", target); + json.put("sentHeaderHex", toHex(sndHeader)); + json.put("sentBodyHex", toHex(sndLog)); + json.put("replyBytes", reply.length); + json.put("replyHexFirst64", toHex(slice(reply, 0, Math.min(64, reply.length)))); + json.put("rcvHeaderRaw", rcvHeader); + json.put("success", rcvHeader.nRetCd() == AbsProtocol.SUCCESS); + json.put("encryption", encMeta); + + System.out.println("-".repeat(10) + json.get("ok")); + + + Object rcvHeaderRaw = json.get("rcvHeaderRaw"); + RcvHeader rcvHeaderMix = (RcvHeader) json.get("rcvHeaderRaw"); + + //building the object + RcvHeaderRaw rcvHeaderRawMix = new RcvHeaderRaw( + rcvHeaderMix.nTxnCd(), + rcvHeaderMix.nRetCd(), + rcvHeaderMix.nNumRecs(), + rcvHeaderMix.nTxnId(), + rcvHeaderMix.cBtMake(), + rcvHeaderMix.size() + ); + // Encryption for the builder + boolean used = encMeta.get("used") instanceof Boolean ? (Boolean) encMeta.get("used") : false; + int utcSeconds = encMeta.get("utcSeconds") instanceof Number ? ((Number) encMeta.get("utcSeconds")).intValue() : 0; + int key = encMeta.get("key") instanceof Number ? ((Number) encMeta.get("key")).intValue() : 0; + String encPasswd = encMeta.get("encPasswd") instanceof String ? (String) encMeta.get("encPasswd") : ""; + Encryption encryption = new Encryption(used, utcSeconds, key, encPasswd); + + Log logDump = null; + + System.out.println("-".repeat(10) + encryption); + // ---- body offset logic (like Node) ---- + int bodyOffset = rcvHeader.size(); + if (reply.length >= bodyOffset + 4) { + int maybeOp = leInt(reply, bodyOffset); + if (maybeOp == AbsProtocol.LOGBT || maybeOp == AbsProtocol.LOG || maybeOp == 0 + || (maybeOp >= 1000 && maybeOp <= 10000)) { + bodyOffset += 4; + json.put("rcvExtraOpCd", maybeOp); + } else { + boolean looksYear = looksYear(reply, bodyOffset); + boolean looksYearFwd = looksYear(reply, bodyOffset + 4); + if (!looksYear && looksYearFwd) bodyOffset += 4; + } + } + if (bodyOffset >= 4 && byteAt(reply, bodyOffset) == (byte)'/') { + if (byteAt(reply, bodyOffset - 4) == '2' && byteAt(reply, bodyOffset - 3) == '0') { + bodyOffset -= 4; + } + } + + json.put("offsetProbe", Map.of( + "bodyOffset", bodyOffset, + "around", new String(slice(reply, Math.max(0, bodyOffset - 8), + Math.min(reply.length, bodyOffset + 16)), StandardCharsets.US_ASCII) + )); + + if ((boolean) json.get("success") && reply.length >= bodyOffset + 20) { + try { + RcvLog log = AbsProtocol.parseRcvLog(reply, bodyOffset); + logDump = new Log( + log.cDateTime(), + log.cUsrNm(), + log.cUsrId(), + log.cSupNm(), + log.cSupId(), + log.cUsrTyp(), + log.fOpenBal(), + log.fTktSalesByVoucher(), + log.fTktSalesByCash(), + log.fTktSalesByMemCard(), + log.nTktSalesByVoucherCount(), + log.nTktSalesByCashCount(), + log.nTktSalesByMemCardCount(), + log.fPayoutByVoucher(), + log.fPayoutByCash(), + log.fPayoutByMemCard(), + log.nPayoutByVoucherCount(), + log.nPayoutByCashCount(), + log.nPayoutByMemCardCount(), + log.fCancelByVoucher(), + log.fCancelByCash(), + log.fCancelByMemCard(), + log.nCancelByVoucherCount(), + log.nCancelByCashCount(), + log.nCancelByMemCardCount(), + log.fDeposit(), + log.fWithdrawAmt(), + log.fVoucherSales(), + log.fVoucherEncash(), + log.fCloseBal(), + log.fSaleTarget(), + log.size() + ); + + if(log.cDateTime() != null){ + // then build the final json response apiResponse + + apiResponse = new ApiResponse( + (boolean)json.get("ok"), + (String)json.get("target"), + (String)json.get("sentHeaderHex"), + (String)json.get("sentBodyHex"), + (int)json.get("replyBytes"), + (String)json.get("replyHexFirst64"), + rcvHeaderRawMix, + (boolean)json.get("success"), + encryption, + logDump + ); + } + + //json.put("log", log); + } catch (Exception ex) { + json.put("parseLogError", ex.toString()); + } + } + + return apiResponse; + } catch (Exception e) { + return null; + } + } + + // ---------- helpers ---------- private static byte[] slice(byte[] a, int off, int end) { diff --git a/struct.txt b/struct.txt new file mode 100644 index 0000000..e69de29