perbaikan response
This commit is contained in:
@@ -33,18 +33,51 @@ func RemovePKCS7Padding(data []byte) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paddingLength := int(data[len(data)-1])
|
paddingLength := int(data[len(data)-1])
|
||||||
if paddingLength > len(data) || paddingLength == 0 {
|
|
||||||
|
// Validasi padding length
|
||||||
|
if paddingLength > len(data) || paddingLength == 0 || paddingLength > 16 {
|
||||||
log.Printf("RemovePKCS7Padding: Invalid padding length: %d, data length: %d", paddingLength, len(data))
|
log.Printf("RemovePKCS7Padding: Invalid padding length: %d, data length: %d", paddingLength, len(data))
|
||||||
return data // Return original data if padding is invalid
|
// Coba kembalikan data tanpa byte terakhir jika padding tampak salah
|
||||||
|
if len(data) > 1 {
|
||||||
|
return data[:len(data)-1]
|
||||||
|
}
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify all padding bytes are correct
|
// Verify all padding bytes are correct
|
||||||
for i := len(data) - paddingLength; i < len(data); i++ {
|
paddingStart := len(data) - paddingLength
|
||||||
|
for i := paddingStart; i < len(data); i++ {
|
||||||
if data[i] != byte(paddingLength) {
|
if data[i] != byte(paddingLength) {
|
||||||
log.Printf("RemovePKCS7Padding: Invalid padding byte at position %d", i)
|
log.Printf("RemovePKCS7Padding: Invalid padding byte at position %d, expected %d, got %d", i, paddingLength, data[i])
|
||||||
return data // Return original data if padding is invalid
|
// Jika padding tidak valid, coba cari padding yang benar
|
||||||
|
return findValidPadding(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data[:len(data)-paddingLength]
|
result := data[:paddingStart]
|
||||||
|
log.Printf("RemovePKCS7Padding: Successfully removed %d padding bytes", paddingLength)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi baru untuk mencari padding yang valid
|
||||||
|
func findValidPadding(data []byte) []byte {
|
||||||
|
dataLen := len(data)
|
||||||
|
|
||||||
|
// Coba berbagai kemungkinan padding length (1-16)
|
||||||
|
for padLen := 1; padLen <= 16 && padLen <= dataLen; padLen++ {
|
||||||
|
valid := true
|
||||||
|
for i := dataLen - padLen; i < dataLen; i++ {
|
||||||
|
if data[i] != byte(padLen) {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if valid {
|
||||||
|
log.Printf("RemovePKCS7Padding: Found valid padding of length %d", padLen)
|
||||||
|
return data[:dataLen-padLen]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("RemovePKCS7Padding: No valid padding found, returning original data")
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
"api-service/internal/config"
|
"api-service/internal/config"
|
||||||
"api-service/internal/models/vclaim/peserta"
|
"api-service/internal/models/vclaim/peserta"
|
||||||
@@ -18,16 +19,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// cleanResponse removes invalid characters and BOM from the response string
|
// cleanResponse removes invalid characters and BOM from the response string
|
||||||
func cleanResponse(resp string) string {
|
|
||||||
// Remove UTF-8 BOM
|
|
||||||
resp = strings.TrimPrefix(resp, "\xef\xbb\xbf")
|
|
||||||
resp = strings.TrimPrefix(resp, "\ufeff")
|
|
||||||
// Remove null characters
|
|
||||||
resp = strings.ReplaceAll(resp, "\x00", "")
|
|
||||||
// Trim whitespace
|
|
||||||
resp = strings.TrimSpace(resp)
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
||||||
// VClaimService interface for VClaim operations
|
// VClaimService interface for VClaim operations
|
||||||
type VClaimService interface {
|
type VClaimService interface {
|
||||||
@@ -201,6 +192,17 @@ func (s *Service) processResponse(res *http.Response) (*ResponDTOVclaim, error)
|
|||||||
Int("key_length", len(decryptionKey)).
|
Int("key_length", len(decryptionKey)).
|
||||||
Msg("Decryption key components")
|
Msg("Decryption key components")
|
||||||
|
|
||||||
|
// // Decrypt response
|
||||||
|
// consID, secretKey, userKey, tstamp, _ := s.config.SetHeader()
|
||||||
|
// decryptionKey := GenerateBPJSKey(consID, tstamp, secretKey) // Menggunakan fungsi baru
|
||||||
|
// log.Debug().
|
||||||
|
// Str("consID", consID).
|
||||||
|
// Str("tstamp", tstamp).
|
||||||
|
// Str("userKey", userKey).
|
||||||
|
// Str("secretKey", secretKey).
|
||||||
|
// Int("key_length", len(decryptionKey)).
|
||||||
|
// Msg("Decryption key components")
|
||||||
|
|
||||||
respDecrypt, err := ResponseVclaim(respMentah.Response, decryptionKey)
|
respDecrypt, err := ResponseVclaim(respMentah.Response, decryptionKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to decrypt response")
|
log.Error().Err(err).Msg("Failed to decrypt response")
|
||||||
@@ -211,9 +213,28 @@ func (s *Service) processResponse(res *http.Response) (*ResponDTOVclaim, error)
|
|||||||
if respDecrypt != "" {
|
if respDecrypt != "" {
|
||||||
// Clean the decrypted response
|
// Clean the decrypted response
|
||||||
respDecrypt = cleanResponse(respDecrypt)
|
respDecrypt = cleanResponse(respDecrypt)
|
||||||
if err := json.Unmarshal([]byte(respDecrypt), &finalResp.Response); err != nil {
|
|
||||||
// If JSON unmarshal fails, store as string
|
// Try multiple cleaning strategies
|
||||||
log.Warn().Err(err).Msg("Failed to unmarshal decrypted response, storing as string")
|
cleaningStrategies := []string{
|
||||||
|
respDecrypt,
|
||||||
|
strings.TrimLeft(respDecrypt, "\ufeff\xfe\xef\xbb\xbf"),
|
||||||
|
strings.TrimLeftFunc(respDecrypt, func(r rune) bool { return r < 32 && r != '\n' && r != '\r' && r != '\t' }),
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonParseSuccess bool
|
||||||
|
for i, cleaned := range cleaningStrategies {
|
||||||
|
if err := json.Unmarshal([]byte(cleaned), &finalResp.Response); err == nil {
|
||||||
|
log.Info().
|
||||||
|
Int("strategy", i+1).
|
||||||
|
Msg("Successfully parsed JSON with cleaning strategy")
|
||||||
|
jsonParseSuccess = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !jsonParseSuccess {
|
||||||
|
// If all JSON parsing fails, store as string
|
||||||
|
log.Warn().Msg("All JSON parsing strategies failed, storing as string")
|
||||||
finalResp.Response = respDecrypt
|
finalResp.Response = respDecrypt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -477,3 +498,80 @@ func PostRequest(endpoint string, cfg interface{}, data interface{}) interface{}
|
|||||||
|
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
func cleanResponse(s string) string {
|
||||||
|
// Remove UTF-8 BOM dan variasi BOM lainnya
|
||||||
|
s = strings.TrimPrefix(s, "\xef\xbb\xbf") // UTF-8 BOM
|
||||||
|
s = strings.TrimPrefix(s, "\ufeff") // Unicode BOM
|
||||||
|
s = strings.TrimPrefix(s, "\ufffe") // Unicode BOM (reverse)
|
||||||
|
s = strings.TrimPrefix(s, "\xff\xfe") // UTF-16 LE BOM
|
||||||
|
s = strings.TrimPrefix(s, "\xfe\xff") // UTF-16 BE BOM
|
||||||
|
|
||||||
|
// Remove karakter control dan non-printable
|
||||||
|
var result strings.Builder
|
||||||
|
for _, r := range s {
|
||||||
|
if r >= 32 && r <= 126 || r == '\n' || r == '\r' || r == '\t' {
|
||||||
|
result.WriteRune(r)
|
||||||
|
} else if r > 126 && unicode.IsPrint(r) {
|
||||||
|
// Allow Unicode printable characters
|
||||||
|
result.WriteRune(r)
|
||||||
|
}
|
||||||
|
// Skip semua karakter lainnya (termasuk BOM fragments)
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned := result.String()
|
||||||
|
cleaned = strings.TrimSpace(cleaned)
|
||||||
|
|
||||||
|
// Cari dan ekstrak JSON yang valid
|
||||||
|
if idx := strings.Index(cleaned, "{"); idx >= 0 {
|
||||||
|
cleaned = cleaned[idx:]
|
||||||
|
// Find matching closing brace
|
||||||
|
if endIdx := findMatchingBrace(cleaned); endIdx > 0 {
|
||||||
|
cleaned = cleaned[:endIdx+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("cleanResponse: Final cleaned length: %d", len(cleaned))
|
||||||
|
log.Printf("cleanResponse: Final result preview: %s", cleaned[:min(200, len(cleaned))])
|
||||||
|
return cleaned
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi helper untuk menemukan closing brace yang matching
|
||||||
|
func findMatchingBrace(s string) int {
|
||||||
|
if len(s) == 0 || s[0] != '{' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
braceCount := 0
|
||||||
|
inString := false
|
||||||
|
escaped := false
|
||||||
|
|
||||||
|
for i, char := range s {
|
||||||
|
if escaped {
|
||||||
|
escaped = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if char == '\\' {
|
||||||
|
escaped = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if char == '"' && !escaped {
|
||||||
|
inString = !inString
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !inString {
|
||||||
|
if char == '{' {
|
||||||
|
braceCount++
|
||||||
|
} else if char == '}' {
|
||||||
|
braceCount--
|
||||||
|
if braceCount == 0 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ services:
|
|||||||
bynokartu:
|
bynokartu:
|
||||||
methods: ["GET"]
|
methods: ["GET"]
|
||||||
path: "/peserta/:nokartu"
|
path: "/peserta/:nokartu"
|
||||||
get_routes: "/Peserta/nokartu/:nokartu"
|
get_routes: "/nokartu/:nokartu"
|
||||||
# post_routes: "/Peserta/nokartu/:nokartu"
|
# post_routes: "/Peserta/nokartu/:nokartu"
|
||||||
# put_routes: "/Peserta/nokartu/:nokartu"
|
# put_routes: "/Peserta/nokartu/:nokartu"
|
||||||
# delete_routes: "/Peserta/nokartu/:nokartu"
|
# delete_routes: "/Peserta/nokartu/:nokartu"
|
||||||
get_path: "/peserta/:nokartu"
|
get_path: "/Peserta/nokartu/:nokartu/tglSEP/:tglSEP"
|
||||||
# post_path: "/peserta"
|
# post_path: "/peserta"
|
||||||
# put_path: "/peserta/:nokartu"
|
# put_path: "/peserta/:nokartu"
|
||||||
# delete_path: "/peserta/:nokartu"
|
# delete_path: "/peserta/:nokartu"
|
||||||
@@ -45,11 +45,11 @@ services:
|
|||||||
bynik:
|
bynik:
|
||||||
methods: ["GET"]
|
methods: ["GET"]
|
||||||
path: "/peserta/nik/:nik"
|
path: "/peserta/nik/:nik"
|
||||||
get_routes: "/Peserta/nik/:nik"
|
get_routes: "/nik/:nik"
|
||||||
# post_routes: "/Peserta/nik/:nik"
|
# post_routes: "/Peserta/nik/:nik"
|
||||||
# put_routes: "/Peserta/nik/:nik"
|
# put_routes: "/Peserta/nik/:nik"
|
||||||
# delete_routes: "/Peserta/nik/:nik"
|
# delete_routes: "/Peserta/nik/:nik"
|
||||||
get_path: "/peserta/nik/:nik"
|
get_path: "/Peserta/nik/:nik/tglSEP/:tglSEP"
|
||||||
# post_path: "/peserta"
|
# post_path: "/peserta"
|
||||||
# put_path: "/peserta/nik/:nik"
|
# put_path: "/peserta/nik/:nik"
|
||||||
# delete_path: "/peserta/nik/:nik"
|
# delete_path: "/peserta/nik/:nik"
|
||||||
Reference in New Issue
Block a user