moov-io / iso8583

A golang implementation to marshal and unmarshal iso8583 message.
https://moov.io
Apache License 2.0
349 stars 103 forks source link

Helps to understand the message Unpack #69

Closed Juniornewxt closed 3 years ago

Juniornewxt commented 3 years ago

I get the message from the server "01360210723804010AC000081641341100081378100030000000000006630624185210000001185210062405104008911751800000196POS1111100000000000"

but the unpack result doesn't seem correct to me : 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30

Below is the example code I set up

package main

import ( "fmt" "github.com/moov-io/iso8583" "github.com/moov-io/iso8583/encoding" "github.com/moov-io/iso8583/field" "github.com/moov-io/iso8583/padding" "github.com/moov-io/iso8583/prefix" )

func NewSpec() *iso8583.MessageSpec { return &iso8583.MessageSpec{ Fields: map[int]field.Field{ 0: field.NewString(&field.Spec{ Length: 8, Description: "Message Type Indicator", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), 1: field.NewBitmap(&field.Spec{ Description: "Bitmap", Enc: encoding.Hex, Pref: prefix.Hex.Fixed, }), // 2: field.NewString(&field.Spec{ // Length: 19, // Description: "Primary Account Number", // Enc: encoding.ASCII, // Pref: prefix.ASCII.LL, // }), 3: field.NewNumeric(&field.Spec{ Length: 6, Description: "Processing Code", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 4: field.NewNumeric(&field.Spec{ Length: 12, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 7: field.NewNumeric(&field.Spec{ Length: 10, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 11: field.NewNumeric(&field.Spec{ Length: 6, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 12: field.NewNumeric(&field.Spec{ Length: 6, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 13: field.NewNumeric(&field.Spec{ Length: 4, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), //14: field.NewNumeric(&field.Spec{ // Length: 4, // Description: "Transaction Amount", // Enc: encoding.ASCII, // Pref: prefix.ASCII.Fixed, // Pad: padding.Left('0'), //}), 22: field.NewNumeric(&field.Spec{ Length: 3, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), //23: field.NewNumeric(&field.Spec{ // Length: 3, // Description: "Transaction Amount", // Enc: encoding.ASCII, // Pref: prefix.ASCII.Fixed, // Pad: padding.Left('0'), //}), 32: field.NewString(&field.Spec{ Length: 11, Description: "Field 32", Enc: encoding.ASCII, Pref: prefix.ASCII.LL, }), 35: field.NewString(&field.Spec{ Length: 37, Description: "Field 32", Enc: encoding.ASCII, Pref: prefix.ASCII.LL, }), 37: field.NewNumeric(&field.Spec{ Length: 12, Description: "NSU", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 41: field.NewString(&field.Spec{ Length: 8, Description: "TERMINAL", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), //39: field.NewString(&field.Spec{ // Length: 2, // Description: "Field 39", // Enc: encoding.ASCII, // Pref: prefix.ASCII.Fixed, // Pad: padding.Left('0'), //}), 42: field.NewString(&field.Spec{ Length: 15, Description: "Field 42", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, }), //45: field.NewString(&field.Spec{ // Length: 76, // Description: " 1", // Enc: encoding.ASCII, // Pref: prefix.ASCII.LL, //}), 47: field.NewString(&field.Spec{ Length: 999, Description: "DADOS ADD", Enc: encoding.ASCII, Pref: prefix.ASCII.LLL, }), //48: field.NewString(&field.Spec{ // Length: 999, // Description: "47", // Enc: encoding.ASCII, // Pref: prefix.ASCII.LLL, //}), 49: field.NewNumeric(&field.Spec{ Length: 3, Description: "Transaction Amount", Enc: encoding.ASCII, Pref: prefix.ASCII.Fixed, Pad: padding.Left('0'), }), 52: field.NewString(&field.Spec{ Length: 16, Description: "Field 52", Enc: encoding.Binary, Pref: prefix.ASCII.Fixed, }), //55: field.NewString(&field.Spec{ // Length: 999, // Description: "CHIP EMV", // Enc: encoding.ASCII, // Pref: prefix.ASCII.LLL, //}), 61: field.NewString(&field.Spec{ Length: 999, Description: " ADC", Enc: encoding.ASCII, Pref: prefix.ASCII.LLL, //}), //70: field.NewNumeric(&field.Spec{ // Length: 3, // Description: "Transaction Amount", // Enc: encoding.ASCII, // Pref: prefix.ASCII.Fixed, // Pad: padding.Left('0'), }), }, }

}

func main() { test() }

func test() { want := "01360210723804010AC000081641341100081378100030000000000006630624185210000001185210062405104008911751800000196POS1111100000000000"

spec := NewSpec()

message := iso8583.NewMessage(spec)

message.Unpack([]byte(want))

message.GetMTI() 
message.GetString(3) 
message.GetString(4) 
message.GetString(7) 
message.GetString(11)
message.GetString(12)
message.GetString(13)

// set your values
c, err := message.Pack()
if err != nil {
    panic(err)

}
fmt.Printf("% x\n", c)

}

vtolstov commented 3 years ago

what server (software) sends this message?

Juniornewxt commented 3 years ago

is a proprietary software, I send the message in hex "golang moov-io" through tcp ip on the network, it returns this message to me I believe it is an ascii.

It contains the information whether it was authorized or not, in this example it was denied.

I would like to treat this answer in such a way that it shows on screen the reason for the denial or authorization.

vtolstov commented 3 years ago

what kind of software (tieto, altavista, way4) ? usually message contains length followed by data, for example in tieto card processing message len in first 6 chars

Juniornewxt commented 3 years ago

In this case the length is the first 4 digits before the mti0210 notice that in the mti declaration I put it with 8 digits, because that was the way I found to put the message size at the time I send it.

Juniornewxt commented 3 years ago

size 0136 mti 0210

alovak commented 3 years ago

@Juniornewxt thanks for sharing your example. If you know the format and the length of the ISO header (from your example it seems it's 4 bytes)

In provided example, the length should be 136 or 132 (136 - header length itself), but it's 124. Can you read more bytes from the input?

Also, why all other fields in spec are commented? If the spec that was used to generate message on server is different from the spec on the client, then unpack/pack test will fail as result will be different.

wadearnold commented 3 years ago

@Juniornewxt is there a reason that you are using a custom spec? If so can you upload the spec file?

isomessage := iso8583.NewMessage(iso8583.Spec87)
err = isomessage.Unpack([]byte("01360210723804010AC000081641341100081378100030000000000006630624185210000001185210062405104008911751800000196POS1111100000000000"))
if err != nil {
    t.Errorf("failed to pack unpacked message: %v", err)
}

This is the error that I receive using a standard spec.

--- FAIL: TestIssue69 (0.00s)
    /Users/wadearnold/Documents/GitHub/wadearnold/iso8583/test/issues/issue69_test.go:23: failed to pack unpacked message: failed to unpack field 57 (Reserved (National)): failed to decode length: strconv.Atoi: parsing "6PO": invalid syntax
FAIL

@alovak pointed out that your message length is not as long as the message header states it should be. Messages headers were used on systems written in programming languages where the buffer length had to be defined before the input could be read. IE set a buffer for 4 to read the header and then make a new buffer of length header to read the rest of the bytes. In those languages, you needed to read the exact number of bytes in the buffer. That's why it is strange that they don't match.

Juniornewxt commented 3 years ago

new exemplo 01150210323800010AC000080030000000000006630706101623000001101623070604008910162341603896JUNI0SIM00000000000999900504.10

Juniornewxt commented 3 years ago

It seems to me that you can now "33 32 33 38 30 30 30 31 30 41 43 30 30 30 38 30 30 33 30 30 30 30 30 30 30 30 30 30 30 36 33 30 37 30 36 31 30 31 36 32 33 30 30 30 30 30 31 31 30 31 36 32 33 30 37 30 36 30 34 30 30 38 39 31 30 31 36 32 33 34 31 36 30 33 38 39 36 4a 55 4e 49 30 53 49 4d 30 30 30 30 30 30 30 30 30 30 39 39 39 39 30 30 35 30 34 2e 31 30 " my problem was in the "spec", I thought because I declared below " message.GetMTI() message.GetString(3) ..." I didn't have to worry that it wouldn't be used in the "spec", but it doesn't seem to work.

Now another question arises, how do I show something like this on the screen:

BIT[003]: 003000 BIT[004]: 000000000663 BIT[007]: 0706104558 BIT[011]: 000001 BIT[012]: 104558 BIT[013]: 0706 BIT[032]: 0089 BIT[037]: 104558716844 BIT[039]: 96 BIT[041]: JUNI0SIM BIT[042]: 0000000000009999 BIT[061]: 04.10

alovak commented 3 years ago

@Juniornewxt I've created a proposal for message reader that understands ISO Header now. You can try this branch: add-iso-header by go get github.com/moov-io/iso8583@add-iso-header. Then, when you have a message with header you have to do following to unpack it:


message := iso8583.NewMessage(spec)
// set ISO header. BaseHeader is ASCII 4 bytes length
message.SetHeader(header.NewBaseHeader())

packed := []byte("01150210323800010AC000080030000000000006630706101623000001101623070604008910162341603896JUNI0SIM00000000000999900504.10")

message.Read(bytes.NewReader(packed))

// now you should be able to access your fields without manually cutting 4 bytes of your input

message.GetString(3) // => ....

Please, let me know if it works for you.

alovak commented 3 years ago

@Juniornewxt do you mean some kind of well-formatted output of the message on the screen? Is the close to what you want: https://github.com/moov-io/iso8583/issues/72?

Now another question arises, how do I show something like this on the screen:

BIT[003]: 003000 BIT[004]: 000000000663 BIT[007]: 0706104558 BIT[011]: 000001 BIT[012]: 104558 BIT[013]: 0706 BIT[032]: 0089 BIT[037]: 104558716844 BIT[039]: 96 BIT[041]: JUNI0SIM BIT[042]: 0000000000009999 BIT[061]: 04.10

Juniornewxt commented 3 years ago

@alovak

72 Yes, but I didn't understand how to make this work, do you have any examples?

alovak commented 3 years ago

It's not implemented yet. I'll close this ticket. Please, subscribe for the #72. We will close it when we are done with dump/screen output.

Juniornewxt commented 3 years ago

Perfect! Tks.

alovak commented 3 years ago

@Juniornewxt we released CLI that displays message in human-readable format. More information here: https://github.com/moov-io/iso8583/#cli

let me know if it's useful for you.

Juniornewxt commented 3 years ago

My goal is to read the message inside the go program, because depending on the answer, I have to make another call and in return put the message on screen in a way that is easily understood.

I don't know if this solution solves my problem. 🙁


De: Pavel Gabriel @.> Enviado: quinta-feira, 15 de julho de 2021 10:30 Para: moov-io/iso8583 @.> Cc: Juniornewxt @.>; Mention @.> Assunto: Re: [moov-io/iso8583] Helps to understand the message Unpack (#69)

@Juniornewxthttps://github.com/Juniornewxt we released CLI that displays message in human-readable format. More information here: https://github.com/moov-io/iso8583/#cli

let me know if it's useful for you.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/moov-io/iso8583/issues/69#issuecomment-880584438, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ANJQOXOM64YMWJOELG7I6UTTX22ERANCNFSM47U7JAVQ.

alovak commented 3 years ago

@Juniornewxt here is the code that you can use inside your program to debug ISO 8583 message:

First, update your package: go get github.com/moov-io/iso8583@latest

Then:

import "github.com/moov-io/iso8583/cmd/iso8583/describe"

func main() {
    // your code that creates iso8583.Message
    // ...

    // now you can dump message to the STDOUT
    describe.Message(os.Stdout, message)

I hope that it helps.

Juniornewxt commented 3 years ago

@alovak Thanks, it looks really good, I managed to use it. Fantastic! You guys do a great job.

Juniornewxt commented 3 years ago

@alovak a curiosity of mine. I can somehow change the words F003, F004 ... for example by DE03, DE04 or simply removing this information?

alovak commented 3 years ago

I'm not sure about it. At least for now we will keep it as is.

Juniornewxt commented 3 years ago

@alovak No problem, that's great, thank you friend.