Skip to content

Commit 6fec6d1

Browse files
authored
Merge pull request #195 from voxter/master-pr-binary-cert-and-key
Allow binary cert/key in apns_connection like v1
2 parents 87b1dce + d9143b8 commit 6fec6d1

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ The other way is send all that info as a parameter to `apns:connect/1` function
7272
}.
7373
```
7474

75-
APNs allows two connection types, one is using `Provider Certificates`. If you want to use that way make sure you fill the `certfile` and `keyfile`. Those are paths to the `Provider Certificated` and the `Private Key` both provided by Apple. We need them in `.pem` format, here is an example of how to convert them, check the [certificates](https://blog.serverdensity.com/how-to-build-an-apple-push-notification-provider-server-tutorial/) section.
75+
APNs allows two connection types, one is using `Provider Certificates`. The first certificate option is to supply cert paths in `certfile` and `keyfile`. Alternatively, you can supply a cert binary in `certdata` and a `keydata()`-type tuple (see: https://github.com/inaka/apns4erl/blob/master/src/apns_connection.erl#L64) in `keydata`. Certs are the `Provider Certificates` and the keys are the `Private Key` both provided by Apple. We need them in `.pem` format, here is an example of how to convert them, check the [certificates](https://blog.serverdensity.com/how-to-build-an-apple-push-notification-provider-server-tutorial/) section.
7676

7777
The other way to connect against APNs is using `Provider Authentication Tokens`, for this choice you must fill the field `token_keyfile`. This is a path to the Authentication Key provided by Apple. This is in `.p8` format and it doesn't need conversion.
7878

@@ -101,13 +101,15 @@ After running `apns4erl` app we can start creating connections. As we mentioned
101101
#{ name := name()
102102
, apple_host := host()
103103
, apple_port := inet:port_number()
104+
, certdata => binary()
104105
, certfile => path()
106+
, keydata => keydata()
105107
, keyfile => path()
106108
, timeout => integer()
107109
, type := type()
108110
}.
109111
```
110-
where the `type` field indicates if is `cert` or `token`.
112+
where the `type` field indicates if is `certdata`, `cert`, or `token`.
111113

112114
- `apns:connect/2`: The first argument is the type and the second one is the connection's name. In order to use it successfully we have to fill the `config` file before, as explained in `how to use it?` section.
113115

src/apns_connection.erl

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
, name/1
2828
, host/1
2929
, port/1
30+
, certdata/1
3031
, certfile/1
32+
, keydata/1
3133
, keyfile/1
3234
, type/1
3335
, http2_connection/1
@@ -58,11 +60,16 @@
5860
-type host() :: string() | inet:ip_address().
5961
-type path() :: string().
6062
-type notification() :: binary().
61-
-type type() :: cert | token.
63+
-type type() :: certdata | cert | token.
64+
-type keydata() :: {'RSAPrivateKey' | 'DSAPrivateKey' | 'ECPrivateKey' |
65+
'PrivateKeyInfo'
66+
, binary()}.
6267
-type connection() :: #{ name := name()
6368
, apple_host := host()
6469
, apple_port := inet:port_number()
70+
, certdata => binary()
6571
, certfile => path()
72+
, keydata => keydata()
6673
, keyfile => path()
6774
, timeout => integer()
6875
, type := type()
@@ -90,6 +97,21 @@ start_link(Connection, Client) ->
9097

9198
%% @doc Builds a connection() map from the environment variables.
9299
-spec default_connection(type(), name()) -> connection().
100+
default_connection(certdata, ConnectionName) ->
101+
{ok, Host} = application:get_env(apns, apple_host),
102+
{ok, Port} = application:get_env(apns, apple_port),
103+
{ok, Cert} = application:get_env(apns, certdata),
104+
{ok, Key} = application:get_env(apns, keydata),
105+
{ok, Timeout} = application:get_env(apns, timeout),
106+
107+
#{ name => ConnectionName
108+
, apple_host => Host
109+
, apple_port => Port
110+
, certdata => Cert
111+
, keydata => Key
112+
, timeout => Timeout
113+
, type => certdata
114+
};
93115
default_connection(cert, ConnectionName) ->
94116
{ok, Host} = application:get_env(apns, apple_host),
95117
{ok, Port} = application:get_env(apns, apple_port),
@@ -256,10 +278,18 @@ host(#{apple_host := Host}) ->
256278
port(#{apple_port := Port}) ->
257279
Port.
258280

281+
-spec certdata(connection()) -> binary().
282+
certdata(#{certdata := Cert}) ->
283+
Cert.
284+
259285
-spec certfile(connection()) -> path().
260286
certfile(#{certfile := Certfile}) ->
261287
Certfile.
262288

289+
-spec keydata(connection()) -> keydata().
290+
keydata(#{keydata := Key}) ->
291+
Key.
292+
263293
-spec keyfile(connection()) -> path().
264294
keyfile(#{keyfile := Keyfile}) ->
265295
Keyfile.
@@ -277,6 +307,10 @@ open_http2_connection(Connection) ->
277307
Host = host(Connection),
278308

279309
TransportOpts = case type(Connection) of
310+
certdata ->
311+
Cert = certdata(Connection),
312+
Key = keydata(Connection),
313+
[{cert, Cert}, {key, Key}];
280314
cert ->
281315
Certfile = certfile(Connection),
282316
Keyfile = keyfile(Connection),

test/connection_SUITE.erl

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
]).
88

99
-export([ default_connection/1
10+
, certdata_keydata_connection/1
1011
, connect/1
1112
, connect_without_name/1
1213
, http2_connection_lost/1
@@ -26,6 +27,7 @@
2627

2728
-spec all() -> [atom()].
2829
all() -> [ default_connection
30+
, certdata_keydata_connection
2931
, connect
3032
, connect_without_name
3133
, http2_connection_lost
@@ -77,6 +79,24 @@ default_connection(_Config) ->
7779
token = apns_connection:type(DefaultConnection2),
7880
ok.
7981

82+
-spec certdata_keydata_connection(config()) -> ok.
83+
certdata_keydata_connection(_Config) ->
84+
ConnectionName = my_connection2,
85+
{ok, Host} = application:get_env(apns, apple_host),
86+
{ok, Port} = application:get_env(apns, apple_port),
87+
{ok, Certdata} = application:get_env(apns, certdata),
88+
{ok, Keydata} = application:get_env(apns, keydata),
89+
90+
% certdata type connection
91+
DefaultConnection = apns_connection:default_connection(certdata, ConnectionName),
92+
ConnectionName = apns_connection:name(DefaultConnection),
93+
Host = apns_connection:host(DefaultConnection),
94+
Port = apns_connection:port(DefaultConnection),
95+
Certdata = apns_connection:certdata(DefaultConnection),
96+
Keydata = apns_connection:keydata(DefaultConnection),
97+
certdata = apns_connection:type(DefaultConnection),
98+
ok.
99+
80100
-spec connect(config()) -> ok.
81101
connect(_Config) ->
82102
ok = mock_open_http2_connection(),
@@ -101,7 +121,7 @@ connect_without_name(_Config) ->
101121
-spec http2_connection_lost(config()) -> ok.
102122
http2_connection_lost(_Config) ->
103123
ok = mock_open_http2_connection(),
104-
ConnectionName = my_connection2,
124+
ConnectionName = my_connection3,
105125
{ok, ServerPid} = apns:connect(cert, ConnectionName),
106126

107127
HTTP2Conn = apns_connection:http2_connection(ConnectionName),
@@ -120,7 +140,7 @@ http2_connection_lost(_Config) ->
120140
% Repeat with ceiling 0, for testing coverage
121141
ok = application:set_env(apns, backoff_ceiling, 0),
122142

123-
ConnectionName2 = my_connection3,
143+
ConnectionName2 = my_connection4,
124144
{ok, ServerPid2} = apns:connect(cert, ConnectionName2),
125145
HTTP2Conn3 = apns_connection:http2_connection(ConnectionName2),
126146
true = is_process_alive(HTTP2Conn3),

test/test.config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
apns,
44
[ {apple_host, "api.development.push.apple.com"}
55
, {apple_port, 443}
6+
, {certdata, "DUMMY"}
67
, {certfile, "priv/apns-dev-cert.pem"}
8+
, {keydata, "DUMMY"}
79
, {keyfile, "priv/apns-dev-key-noenc.pem"}
810
, {token_keyfile, "priv/APNsAuthKey_KEYID12345.p8"}
911
, {timeout, 10000}

0 commit comments

Comments
 (0)