-
Notifications
You must be signed in to change notification settings - Fork 384
/
services_push_apns.go
121 lines (97 loc) · 3.04 KB
/
services_push_apns.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
package bertypushrelay
import (
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
"github.com/sideshow/apns2"
"github.com/sideshow/apns2/certificate"
"github.com/sideshow/apns2/payload"
"go.uber.org/zap"
weshnet_errcode "berty.tech/weshnet/pkg/errcode"
"berty.tech/weshnet/pkg/logutil"
"berty.tech/weshnet/pkg/protocoltypes"
"berty.tech/weshnet/pkg/pushtypes"
)
const (
asn1UID = "0.9.2342.19200300.100.1.1"
appleCertDevNamePart = "Apple Development IOS Push Services"
)
type pushDispatcherAPNS struct {
logger *zap.Logger
client *apns2.Client
bundleID string
}
func (d *pushDispatcherAPNS) TokenType() pushtypes.PushServiceTokenType {
return pushtypes.PushServiceTokenType_PushTokenApplePushNotificationService
}
func PushDispatcherLoadAPNSCertificates(logger *zap.Logger, input *string) ([]PushDispatcher, error) {
if input == nil || *input == "" {
return nil, nil
}
paths := strings.Split(*input, ",")
dispatchers := make([]PushDispatcher, len(paths))
for i, path := range paths {
var err error
dispatchers[i], err = pushDispatcherLoadAPNSCertificate(logger, path)
if err != nil {
return nil, err
}
}
return dispatchers, nil
}
func pushDispatcherLoadAPNSCertificate(logger *zap.Logger, path string) (PushDispatcher, error) {
cert, err := certificate.FromP12File(path, "")
if err != nil {
return nil, weshnet_errcode.ErrPushInvalidServerConfig
}
bundleID := ""
for _, kv := range cert.Leaf.Subject.Names {
if kv.Type.String() == asn1UID {
bundleID = kv.Value.(string)
break
}
}
if bundleID == "" {
return nil, weshnet_errcode.ErrPushMissingBundleID
}
production := !strings.Contains(cert.Leaf.Subject.CommonName, appleCertDevNamePart)
client := apns2.NewClient(cert)
if production {
client = client.Production()
} else {
client = client.Development()
}
return &pushDispatcherAPNS{
logger: logger.Named("apns"),
bundleID: bundleID,
client: client,
}, nil
}
func (d *pushDispatcherAPNS) Dispatch(data []byte, receiver *protocoltypes.PushServiceReceiver) error {
token := hex.EncodeToString(receiver.Token)
secretToken := fmt.Sprintf("%.10s...", token)
pushPayload := payload.NewPayload()
pushPayload.Custom(pushtypes.ServicePushPayloadKey, base64.RawURLEncoding.EncodeToString(data))
pushPayload.MutableContent()
pushPayload.AlertLocKey("BertyPushMessage")
// @TODO(gfanton): maybe add a body message ?
notification := &apns2.Notification{}
notification.DeviceToken = token
notification.Topic = d.bundleID
notification.Payload = pushPayload
notification.PushType = apns2.PushTypeAlert
d.logger.Debug("apns notification",
logutil.PrivateString("token device", secretToken),
zap.String("bundleid", d.bundleID))
response, err := d.client.Push(notification)
if err != nil {
return weshnet_errcode.ErrPushProvider.Wrap(err)
} else if response.StatusCode != 200 {
return weshnet_errcode.ErrPushProvider.Wrap(fmt.Errorf("apns: status %d, reason %s", response.StatusCode, response.Reason))
}
return nil
}
func (d *pushDispatcherAPNS) BundleID() string {
return d.bundleID
}