-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
123 lines (105 loc) · 4.07 KB
/
handler.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
package main
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"net/url"
"os"
"reflect"
"strings"
)
// https://tech.yandex.ru/money/doc/dg/reference/notification-p2p-incoming-docpage/
// https://yoomoney.ru/transfer/myservices/http-notification
// https://yandex.ru/dev/money/apps/?_openstat=settings%3Bother%3Bapps%3Bapi
// При получении уведомления всегда проверяйте статус входящего перевода по значениям полей unaccepted и codepro.
// Если unaccepted=true, то перевод еще не зачислен на счет получателя.
// Чтобы его принять, получателю нужно совершить дополнительные действия.
// Например, освободить место на счете, если достигнут лимит доступного остатка.
// Или указать код протекции, если он необходим для получения перевода.
// Если codepro=true, то перевод защищен кодом протекции.
// Чтобы получить такой перевод, пользователю необходимо ввести код протекции.
func YandexMoneyIncomingPush(rbody, yaKey string) {
vs, err := url.ParseQuery(rbody)
if err != nil {
fmt.Printf("YandexMoneyIncomingPush ParseQuery error: %s\n", err)
// в случае ошибок здесь всегда возвращаем 200 ОК
return
}
yap := &YaParams{}
yap.ParsePostForm(vs)
fmt.Printf("Received payment notification: %+v\n", yap)
if err := yap.CheckSha1(yaKey); err != nil {
fmt.Printf("CheckSha1 error: %s\n", err)
return
}
m := NewMailer(
os.Getenv("MSRV"),
os.Getenv("MLGN"),
os.Getenv("MPSW"),
)
sendmail(yap.Email, yap.Label, yap.WithDrawAmount, m)
}
func sendmail(eml, invid, amnt string, mlr *Mailer) {
if eml != "" {
if err := mlr.Send(eml, "Получен перевод средств по счету "+invid,
fmt.Sprintf(`Получен перевод средств по счету %s на сумму %s`,
invid, amnt)); err != nil {
fmt.Printf("Sending mail for %q about payment for invoice %q error: %s\n", eml, invid, err)
return
}
}
if err := mlr.Send(os.Getenv("MLCC"), "Получен перевод средств по счету "+invid,
fmt.Sprintf(`Получен перевод средств от имени %s по счету %s на сумму %s`,
eml, invid, amnt)); err != nil {
fmt.Printf("Sending mail for admin about payment for invoice %q error: %s\n", invid, err)
return
}
}
type YaParams struct {
NotificationType string `form:"notification_type"`
OperationId string `form:"operation_id"`
Amount string `form:"amount"`
Currency string `form:"currency"`
Datetime string `form:"datetime"`
Sender string `form:"sender"`
Codepro string `form:"codepro"`
Label string `form:"label"`
WithDrawAmount string `form:"withdraw_amount"`
Sha1Hash string `form:"sha1_hash"`
Email string `form:"email"`
Lastname string `form:"lastname"`
Firstname string `form:"firstname"`
Fathersname string `form:"fathersname"`
}
func (yp *YaParams) ParsePostForm(data url.Values) {
typ := reflect.TypeOf(yp).Elem()
val := reflect.ValueOf(yp).Elem()
for i := 0; i < typ.NumField(); i++ {
typeField := typ.Field(i)
structField := val.Field(i)
if structField.CanSet() {
inputFieldName := typeField.Tag.Get("form")
if inputFieldName != "" {
structField.SetString(data.Get(inputFieldName))
}
}
}
}
func (yp *YaParams) CheckSha1(nsecret string) error {
str := yp.NotificationType + "&" +
yp.OperationId + "&" +
yp.Amount + "&" +
yp.Currency + "&" +
yp.Datetime + "&" +
yp.Sender + "&" +
yp.Codepro + "&" +
nsecret + "&" +
yp.Label
hasher := sha1.New()
hasher.Write([]byte(str))
sha := hex.EncodeToString(hasher.Sum(nil))
if !strings.EqualFold(sha, yp.Sha1Hash) {
return fmt.Errorf("not equal sign hash: %q != %q", sha, yp.Sha1Hash)
}
return nil
}