-
Notifications
You must be signed in to change notification settings - Fork 2
/
pusher.go
151 lines (124 loc) · 3.58 KB
/
pusher.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
package pusher
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"appengine/urlfetch"
"github.com/secretinc/server/common"
"github.com/secretinc/server/common/integrations"
"github.com/secretinc/server/core/env"
)
type pusherEvent struct {
Name string `json:"name"`
Data interface{} `json:"data"`
Channel string `json:"channel"`
SocketId string `json:"socket_id,omitempty"`
}
const (
noSocketId = ""
baseUrl = "https://api.pusherapp.com"
)
func SafeChannelName(name string) string {
out := ""
for _, c := range name {
if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '=' || c == '@' || c == ',' || c == '.' {
out = out + string(c)
} else {
out = out + "_"
}
}
return out
}
func AppKey(c common.Context) string {
if env.IsLocal() {
return integrations.PusherDevKey
} else if env.IsProd(c) {
return integrations.PusherProdKey
}
return integrations.PusherStagingKey
}
func TriggerEvent(c common.Context, channel, event string, data interface{}) error {
return triggerEvent(c, channel, event, data, noSocketId)
}
func TriggerEventExcluding(c common.Context, channel, event string, data interface{}, socketId string) error {
return triggerEvent(c, channel, event, data, socketId)
}
func triggerEvent(c common.Context, channel, event string, data interface{}, socketId string) error {
if data == nil {
data = map[string]string{}
}
dataBytes, err := json.Marshal(data)
if err != nil {
return err
}
e := pusherEvent{
Channel: channel,
Name: event,
SocketId: socketId,
Data: string(dataBytes),
}
body, err := json.Marshal(e)
if err != nil {
return err
}
client := urlfetch.Client(c)
eventsPath := appPath(c) + "/events"
params := authParams(c, eventsPath, body)
url := fmt.Sprintf("%s?%s", appUrl(c)+"/events", params)
resp, err := client.Post(url, "application/json", bytes.NewBuffer(body))
if err != nil {
c.Errorf("Failed sending to pusher: %s", err)
return err
}
defer resp.Body.Close()
res, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != 200 {
c.Errorf("Unexpected status code: %d with response: %s", resp.StatusCode, string(res))
}
return nil
}
func SignWithSecret(c common.Context, s string) string {
key := appSecret(c)
c.Debugf("Pusher signing %s with key %s", s, key)
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
func authParams(c common.Context, path string, body []byte) string {
hash := common.Md5Hash(string(body))
params := fmt.Sprintf("auth_key=%s&auth_timestamp=%d&auth_version=1.0&body_md5=%s", AppKey(c), common.Now().Unix(), hash)
key := fmt.Sprintf("POST\n%s\n%s", path, params)
sig := SignWithSecret(c, key)
params = fmt.Sprintf("%s&auth_signature=%s", params, sig)
return params
}
func appUrl(c common.Context) string {
return fmt.Sprintf("%s%s", baseUrl, appPath(c))
}
func appPath(c common.Context) string {
return fmt.Sprintf("/apps/%d", appId(c))
}
func appId(c common.Context) int {
if env.IsLocal() {
return integrations.PusherDevAppId
} else if env.IsProd(c) {
return integrations.PusherProdAppId
}
return integrations.PusherStagingAppId
}
func appSecret(c common.Context) string {
if env.IsLocal() {
return integrations.PusherDevSecret
} else if env.IsProd(c) {
return integrations.PusherProdSecret
}
return integrations.PusherStagingSecret
}