Skip to content

Commit f66ecb5

Browse files
committed
feat: add headers
1 parent af8df35 commit f66ecb5

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

lib/web_push_elixir.ex

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ defmodule WebPushElixir do
44
@auth_info "Content-Encoding: auth" <> <<0>>
55
@one_buffer <<1>>
66

7-
def gen_keypair do
7+
def gen_key_pair() do
88
{public, private} = :crypto.generate_key(:ecdh, :prime256v1)
99

10+
{Base.url_encode64(public, padding: false), Base.url_encode64(private, padding: false)}
11+
end
12+
13+
def output_key_pair({public, private}) do
1014
fn ->
11-
Logger.info(%{:public_key => Base.url_encode64(public, padding: false)})
12-
Logger.info(%{:private_key => Base.url_encode64(private, padding: false)})
15+
Logger.info(%{:public_key => public})
16+
Logger.info(%{:private_key => private})
1317

1418
Logger.info(%{:subject => "mailto:[email protected]"})
1519
end
@@ -76,4 +80,31 @@ defmodule WebPushElixir do
7680

7781
cipher_text <> cipher_tag
7882
end
83+
84+
def get_headers(audience, content_encoding, expiration \\ 12 * 3600) do
85+
expiration_timestamp = DateTime.to_unix(DateTime.utc_now()) + expiration
86+
87+
public_key = Base.url_decode64!(System.get_env("PUBLIC_KEY"), padding: false)
88+
private_key = Base.url_decode64!(System.get_env("PRIVATE_KEY"), padding: false)
89+
90+
payload =
91+
%{
92+
aud: audience,
93+
exp: expiration_timestamp,
94+
sub: System.get_env("SUBJECT")
95+
}
96+
|> JOSE.JWT.from_map()
97+
98+
jwk =
99+
{:ECPrivateKey, 1, private_key, {:namedCurve, {1, 2, 840, 10045, 3, 1, 7}}, public_key, nil}
100+
|> JOSE.JWK.from_key()
101+
102+
{_, jwt} = JOSE.JWS.compact(JOSE.JWT.sign(jwk, %{"alg" => "ES256"}, payload))
103+
104+
headers(content_encoding, jwt, System.get_env("PUBLIC_KEY"))
105+
end
106+
107+
defp headers("aesgcm", jwt, pub) do
108+
%{"Authorization" => "WebPush " <> jwt, "Crypto-Key" => "p256ecdsa=" <> pub}
109+
end
79110
end

test/web_push_elixir_test.exs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ defmodule WebPushElixirTest do
1616
@salt_length 16
1717
@server_public_key_length 65
1818

19-
test "it should gen keypair" do
20-
assert capture_log(WebPushElixir.gen_keypair()) =~ "public_key:"
21-
assert capture_log(WebPushElixir.gen_keypair()) =~ "private_key:"
22-
assert capture_log(WebPushElixir.gen_keypair()) =~ "subject:"
23-
assert capture_log(WebPushElixir.gen_keypair()) =~ "mailto:[email protected]"
19+
test "it should output key pair" do
20+
assert capture_log(WebPushElixir.gen_key_pair() |> WebPushElixir.output_key_pair()) =~ "public_key:"
21+
assert capture_log(WebPushElixir.gen_key_pair() |> WebPushElixir.output_key_pair()) =~ "private_key:"
22+
assert capture_log(WebPushElixir.gen_key_pair() |> WebPushElixir.output_key_pair()) =~ "subject:"
23+
assert capture_log(WebPushElixir.gen_key_pair() |> WebPushElixir.output_key_pair()) =~ "mailto:[email protected]"
2424
end
2525

2626
test "it should decode" do
@@ -36,4 +36,24 @@ defmodule WebPushElixirTest do
3636
assert is_binary(response.server_public_key)
3737
assert byte_size(response.server_public_key) == @server_public_key_length
3838
end
39+
40+
test "it should get headers" do
41+
{public, private} = WebPushElixir.gen_key_pair()
42+
43+
System.put_env("PUBLIC_KEY", public)
44+
45+
System.put_env("PRIVATE_KEY", private)
46+
47+
System.put_env("SUBJECT", "mailto:[email protected]")
48+
49+
assert %{"Authorization" => "WebPush " <> jwt, "Crypto-Key" => "p256ecdsa=" <> public_key} =
50+
WebPushElixir.get_headers("http://localhost/", "aesgcm")
51+
52+
jwk =
53+
{:ECPrivateKey, 1, <<>>, {:namedCurve, {1, 2, 840, 10045, 3, 1, 7}},
54+
Base.url_decode64!(public_key, padding: false), nil}
55+
|> JOSE.JWK.from_key()
56+
57+
assert {true, _, _} = JOSE.JWT.verify_strict(jwk, ["ES256"], jwt)
58+
end
3959
end

0 commit comments

Comments
 (0)