Skip to content
This repository was archived by the owner on Jun 6, 2023. It is now read-only.

Commit dc4636b

Browse files
committed
NewService API, simplify certificate loading and pushpackage signing APIs. (#47)
* NewService API extracts topic from cert * pushpackage: use TLS cert for signing simplifying API for signing and certificate loading * push: reorganize code, light refactoring
1 parent f0223e8 commit dc4636b

File tree

14 files changed

+310
-288
lines changed

14 files changed

+310
-288
lines changed

README.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,16 @@ func main() {
7070
password := ""
7171
deviceToken := "c2732227a1d8021cfaf781d71fb2f908c61f5861079a00954a5453f1d0281433"
7272

73-
cert, key, err := certificate.Load(filename, password)
73+
cert, err := certificate.Load(filename, password)
7474
if err != nil {
7575
log.Fatal(err)
7676
}
7777

78-
client, err := push.NewClient(certificate.TLS(cert, key))
78+
service, err := push.NewService(push.Development, cert)
7979
if err != nil {
8080
log.Fatal(err)
8181
}
8282

83-
service := push.Service{
84-
Client: client,
85-
Host: push.Development,
86-
}
87-
8883
p := payload.APS{
8984
Alert: payload.Alert{Body: "Hello HTTP/2"},
9085
Badge: badge.New(42),
@@ -96,6 +91,7 @@ func main() {
9691
}
9792
}
9893
```
94+
9995
#### Headers
10096

10197
You can specify an ID, expiration, priority, and other parameters via the Headers struct.
@@ -145,7 +141,7 @@ Whether you use Push or PushBytes, the underlying HTTP/2 connection to APNS will
145141

146142
#### Error responses
147143

148-
Push and PushBytes may return an `error`. It could be an error the JSON encoding or HTTP request, or it could be a `push.Error` which contains the response from Apple. To access the Reason and Status code, you must convert the `error` to a `push.Error` as follows:
144+
Push and PushBytes may return an `error`. It could be an error the JSON encoding or HTTP request, or it could be a `push.Error` which contains the response from Apple. To access the Reason and HTTP Status code, you must convert the `error` to a `push.Error` as follows:
149145

150146
```go
151147
if e, ok := err.(*push.Error); ok {
@@ -167,7 +163,7 @@ pkg := pushpackage.New(w)
167163
pkg.EncodeJSON("website.json", website)
168164
pkg.File("icon.iconset/icon_128x128@2x.png", "static/icon_128x128@2x.png")
169165
// other icons... (required)
170-
if err := pkg.Sign(cert, privateKey, nil); err != nil {
166+
if err := pkg.Sign(cert, nil); err != nil {
171167
log.Fatal(err)
172168
}
173169
```

certificate/cert.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
package certificate
44

55
import (
6-
"crypto/rsa"
76
"crypto/tls"
87
"crypto/x509"
98
"errors"
@@ -19,40 +18,31 @@ var (
1918
)
2019

2120
// Load a .p12 certificate from disk.
22-
func Load(filename, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
21+
func Load(filename, password string) (tls.Certificate, error) {
2322
p12, err := ioutil.ReadFile(filename)
2423
if err != nil {
25-
return nil, nil, fmt.Errorf("Unable to load %s: %v", filename, err)
24+
return tls.Certificate{}, fmt.Errorf("Unable to load %s: %v", filename, err)
2625
}
2726
return Decode(p12, password)
2827
}
2928

3029
// Decode and verify an in memory .p12 certificate (DER binary format).
31-
func Decode(p12 []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
30+
func Decode(p12 []byte, password string) (tls.Certificate, error) {
3231
// decode an x509.Certificate to verify
3332
privateKey, cert, err := pkcs12.Decode(p12, password)
3433
if err != nil {
35-
return nil, nil, err
34+
return tls.Certificate{}, err
3635
}
3736
if err := verify(cert); err != nil {
38-
return nil, nil, err
37+
return tls.Certificate{}, err
3938
}
4039

41-
// assert that private key is RSA
42-
priv, ok := privateKey.(*rsa.PrivateKey)
43-
if !ok {
44-
return nil, nil, errors.New("expected RSA private key type")
45-
}
46-
return cert, priv, nil
47-
}
48-
49-
// TLS wraps an x509 certificate as a tls.Certificate.
50-
func TLS(cert *x509.Certificate, privateKey *rsa.PrivateKey) tls.Certificate {
40+
// wraps x509 certificate as a tls.Certificate:
5141
return tls.Certificate{
5242
Certificate: [][]byte{cert.Raw},
5343
PrivateKey: privateKey,
5444
Leaf: cert,
55-
}
45+
}, nil
5646
}
5747

5848
// verify checks if a certificate has expired

certificate/cert_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
func TestValidCert(t *testing.T) {
1010
const name = "../testdata/cert.p12"
1111

12-
_, _, err := certificate.Load(name, "")
12+
_, err := certificate.Load(name, "")
1313
if err != nil {
1414
t.Fatal(err)
1515
}
@@ -19,14 +19,14 @@ func TestExpiredCert(t *testing.T) {
1919
// TODO: figure out how to test certificate loading and validation in CI
2020
const name = "../cert-expired.p12"
2121

22-
_, _, err := certificate.Load(name, "")
22+
_, err := certificate.Load(name, "")
2323
if err != certificate.ErrExpired {
2424
t.Fatal("Expected expired cert error, got", err)
2525
}
2626
}
2727

2828
func TestMissingFile(t *testing.T) {
29-
_, _, err := certificate.Load("hide-and-seek.p12", "")
29+
_, err := certificate.Load("hide-and-seek.p12", "")
3030
if err == nil {
3131
t.Fatal("Expected file not found, got", err)
3232
}

example/push/main.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,15 @@ func main() {
1919
flag.StringVar(&environment, "e", "development", "Environment")
2020
flag.Parse()
2121

22-
cert, key, err := certificate.Load(filename, password)
22+
cert, err := certificate.Load(filename, password)
2323
if err != nil {
2424
log.Fatal(err)
2525
}
2626

27-
client, err := push.NewClient(certificate.TLS(cert, key))
27+
service, err := push.NewService(push.Development, cert)
2828
if err != nil {
2929
log.Fatal(err)
3030
}
31-
32-
service := push.Service{
33-
Client: client,
34-
Host: push.Development,
35-
}
3631
if environment == "production" {
3732
service.Host = push.Production
3833
}

example/wallet/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func main() {
3333
flag.StringVar(&intermediate, "i", "", "Path to WWDR intermediate .cer file")
3434
flag.Parse()
3535

36-
cert, privateKey, err := certificate.Load(filename, password)
36+
cert, err := certificate.Load(filename, password)
3737
failIfError(err)
3838

3939
wwdr, err := loadWWDR(intermediate)
@@ -60,6 +60,6 @@ func main() {
6060
pkg.File(name, "./Event.pass/"+name)
6161
}
6262

63-
err = pkg.Sign(cert, privateKey, wwdr)
63+
err = pkg.Sign(cert, wwdr)
6464
failIfError(err)
6565
}

example/website/main.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package main
22

33
import (
4-
"crypto/rsa"
5-
"crypto/x509"
4+
"crypto/tls"
65
"encoding/json"
76
"flag"
87
"html/template"
@@ -22,19 +21,18 @@ var (
2221
website = pushpackage.Website{
2322
Name: "Buford",
2423
PushID: "web.com.github.RobotsAndPencils.buford",
25-
AllowedDomains: []string{"https://9aea51d1.ngrok.io"},
26-
URLFormatString: `https://9aea51d1.ngrok.io/click?q=%@`,
24+
AllowedDomains: []string{"https://e31340d3.ngrok.io"},
25+
URLFormatString: `https://e31340d3.ngrok.io/click?q=%@`,
2726
// AuthenticationToken identifies the user (16+ characters)
2827
AuthenticationToken: "19f8d7a6e9fb8a7f6d9330dabe",
29-
WebServiceURL: "https://9aea51d1.ngrok.io",
28+
WebServiceURL: "https://e31340d3.ngrok.io",
3029
}
3130

32-
// Cert and private key for signing push packages.
33-
cert *x509.Certificate
34-
privateKey *rsa.PrivateKey
31+
// Cert for signing push packages.
32+
cert tls.Certificate
3533

3634
// Service and device token to send push notifications.
37-
service push.Service
35+
service *push.Service
3836
deviceToken string
3937

4038
templates = template.Must(template.ParseFiles("index.html", "request.html"))
@@ -85,7 +83,7 @@ func pushPackagesHandler(w http.ResponseWriter, r *http.Request) {
8583
pkg.File("icon.iconset/icon_32x32.png", "../../testdata/gopher.png")
8684
pkg.File("icon.iconset/icon_16x16@2x.png", "../../testdata/gopher.png")
8785
pkg.File("icon.iconset/icon_16x16.png", "../../testdata/gopher.png")
88-
if err := pkg.Sign(cert, privateKey, nil); err != nil {
86+
if err := pkg.Sign(cert, nil); err != nil {
8987
log.Fatal(err)
9088
}
9189
}
@@ -137,21 +135,16 @@ func main() {
137135
flag.Parse()
138136

139137
var err error
140-
cert, privateKey, err = certificate.Load(filename, password)
138+
cert, err = certificate.Load(filename, password)
141139
if err != nil {
142140
log.Fatal(err)
143141
}
144142

145-
client, err := push.NewClient(certificate.TLS(cert, privateKey))
143+
service, err = push.NewService(push.Production, cert)
146144
if err != nil {
147145
log.Fatal(err)
148146
}
149147

150-
service = push.Service{
151-
Client: client,
152-
Host: push.Production,
153-
}
154-
155148
r := mux.NewRouter()
156149
r.HandleFunc("/", indexHandler).Methods("GET")
157150
r.HandleFunc("/request", requestPermissionHandler)

push/client.go

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)