-
Notifications
You must be signed in to change notification settings - Fork 0
/
callback.go
170 lines (134 loc) · 3.7 KB
/
callback.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package paymentpage
import (
"encoding/json"
"errors"
"strconv"
"strings"
)
// Constants with possible statuses of payment
const (
PaymentStatusSuccess string = "success"
PaymentStatusDecline string = "decline"
PaymentStatusAW3DS string = "awaiting 3ds result"
PaymentStatusAWRedirect string = "awaiting redirect result"
PaymentStatusAWCustomer string = "awaiting customer"
PaymentStatusAWClarification string = "awaiting clarification"
PaymentStatusAWCapture string = "awaiting capture"
PaymentStatusCancelled string = "cancelled"
PaymentStatusRefunded string = "refunded"
PaymentStatusPartiallyRefunded string = "partially refunded"
PaymentStatusProcessing string = "processing"
PaymentStatusError string = "error"
PaymentStatusReversed string = "reversed"
)
// Structure for processing callbacks
type Callback struct {
// Instance for check callback signature
signatureHandler SignatureHandler
// Raw callback data
callbackData string
// Decoded callback data
parsedData map[string]interface{}
// Callback signature
signature string
}
// Return map with payment data
func (c *Callback) GetPayment() interface{} {
return c.GetParam("payment")
}
// Return payment status
func (c *Callback) GetPaymentStatus() interface{} {
status := c.GetParam("payment.status")
return status.(string)
}
// Return our payment id
func (c *Callback) GetPaymentId() interface{} {
id := c.GetParam("payment.id")
switch id := id.(type) {
case float64:
return strconv.FormatFloat(id, 'f', -1, 64)
default:
return id.(string)
}
}
// Get callback param by path name
func (c *Callback) GetParam(pathStr string) interface{} {
path := strings.Split(pathStr, ".")
cbData := c.parsedData
var value interface{}
for _, key := range path {
tmpVal, find := cbData[key]
value = tmpVal
if !find {
break
}
switch value := value.(type) {
case map[string]interface{}:
cbData = value
}
}
return value
}
// Return callback signature
func (c *Callback) getSignature() (string, error) {
if c.signature != "" {
return c.signature, nil
}
signPaths := []string{
"signature",
"general.signature",
}
for _, signPath := range signPaths {
sign := c.GetParam(signPath)
if sign != nil {
c.signature = sign.(string)
return c.signature, nil
}
}
return "", errors.New("signature undefined")
}
// Check that signature is valid
func (c *Callback) checkSignature() error {
signature, err := c.getSignature()
if err != nil {
return err
}
c.removeParam("signature", c.parsedData)
if !c.signatureHandler.Check(signature, c.parsedData) {
return errors.New("invalid signature")
}
return nil
}
// Method for remove value in multilevel map
func (c *Callback) removeParam(name string, data map[string]interface{}) {
if _, find := data[name]; find {
delete(data, name)
}
for _, value := range data {
switch value := value.(type) {
case map[string]interface{}:
c.removeParam(name, value)
}
}
}
// Method for decode callback data
func (c *Callback) parseCallbackData() error {
parseError := json.Unmarshal([]byte(c.callbackData), &c.parsedData)
if parseError != nil {
return errors.New("invalid callback data")
}
return nil
}
// Constructor for Callback structure
func NewCallback(signatureHandler SignatureHandler, callbackData string) (*Callback, error) {
callback := Callback{}
callback.signatureHandler = signatureHandler
callback.callbackData = callbackData
if parseError := callback.parseCallbackData(); parseError != nil {
return &callback, parseError
}
if signatureError := callback.checkSignature(); signatureError != nil {
return &callback, signatureError
}
return &callback, nil
}