Skip to content

Commit

Permalink
Merge pull request #31 from edgurgel/validate-pusher-event
Browse files Browse the repository at this point in the history
Validate pusher event
  • Loading branch information
edgurgel committed May 31, 2015
2 parents fd316df + db8e5e8 commit 2c52a24
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 40 deletions.
21 changes: 8 additions & 13 deletions lib/poxa/event_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,18 @@ defmodule Poxa.EventHandler do
{:ok, body, req} = :cowboy_req.body(req)
case JSX.decode(body) do
{:ok, data} ->
if invalid_data?(data) do
req = :cowboy_req.set_resp_body(@invalid_event_json, req)
{true, req, state}
else
{false, req, %{body: body, data: data}}
case PusherEvent.build(data) do
{:ok, event} -> {false, req, %{body: body, event: event}}
_ ->
req = :cowboy_req.set_resp_body(@invalid_event_json, req)
{true, req, state}
end
_ ->
req = :cowboy_req.set_resp_body(@invalid_event_json, req)
{true, req, state}
end
end

defp invalid_data?(%{"name" => _, "data" => _, "channel" => _}), do: false
defp invalid_data?(%{"name" => _, "data" => _, "channels" => _}), do: false
defp invalid_data?(_), do: true

@authentication_error_json JSX.encode!(%{error: "Authentication error"})
# http://pusher.com/docs/rest_api#authentication
def is_authorized(req, %{body: body} = state) do
Expand All @@ -55,8 +51,8 @@ defmodule Poxa.EventHandler do
end

@invalid_data_size_json JSX.encode!(%{error: "Data key must be smaller than 10KB"})
def valid_entity_length(req, %{data: data} = state) do
valid = byte_size(data["data"]) <= 10_000
def valid_entity_length(req, %{event: event} = state) do
valid = byte_size(event.data) <= 10_000
unless valid do
req = :cowboy_req.set_resp_body(@invalid_data_size_json, req)
end
Expand All @@ -71,8 +67,7 @@ defmodule Poxa.EventHandler do
{[{{"application", "json", []}, :undefined}], req, state}
end

def post(req, %{data: data}) do
event = PusherEvent.build(data)
def post(req, %{event: event}) do
PusherEvent.publish(event)
Event.notify(:api_message, %{channels: event.channels, name: event.name})
req = :cowboy_req.set_resp_body("{}", req)
Expand Down
31 changes: 24 additions & 7 deletions lib/poxa/pusher_event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,37 @@ defmodule Poxa.PusherEvent do
@doc """
Builds the struct based on the decoded JSON from /events endpoint
"""
@spec build(map) :: Poxa.PusherEvent.t
@spec build(map) :: {:ok, Poxa.PusherEvent.t} | {:error, atom}
def build(%{"name" => name, "channels" => channels, "data" => data} = event) do
%Poxa.PusherEvent{channels: channels, data: data, name: name, socket_id: event["socket_id"]}
build_event(channels, data, name, event["socket_id"])
end
def build(%{"name" => name, "channel" => channel, "data" => data} = event) do
%Poxa.PusherEvent{channels: [channel], data: data, name: name, socket_id: event["socket_id"]}
build_event([channel], data, name, event["socket_id"])
end
def build(_), do: {:error, :invalid_pusher_event}

def build_client_event(%{"event" => event, "channel" => channel, "data" => data}, socket_id) do
%Poxa.PusherEvent{channels: [channel], data: data, name: event, socket_id: socket_id}
@doc """
Build client events
"""
@spec build_client_event(map, binary) :: {:ok, Poxa.PusherEvent.t} | {:error, atom}
def build_client_event(%{"event" => name, "channel" => channel, "data" => data}, socket_id) do
build_event([channel], data, name, socket_id)
end
def build_client_event(%{"name" => name, "channel" => channel, "data" => data}, socket_id) do
build_event([channel], data, name, socket_id)
end
def build_client_event(%{"name" => event, "channel" => channel, "data" => data}, socket_id) do
%Poxa.PusherEvent{channels: [channel], data: data, name: event, socket_id: socket_id}

defp build_event(channels, data, name, socket_id) do
event = %Poxa.PusherEvent{channels: channels, data: data, name: name, socket_id: socket_id}
if valid?(event), do: {:ok, event},
else: {:error, :invalid_event}
end

defp valid?(%Poxa.PusherEvent{channels: channels, data: data, name: event, socket_id: socket_id}) do
Enum.all?(channels, &Poxa.Channel.valid?(&1)) and
(!socket_id || Poxa.SocketId.valid?(socket_id))
end
defp valid?(_), do: false

@doc """
Send `message` to `channels` excluding `exclude`
Expand Down
2 changes: 1 addition & 1 deletion lib/poxa/websocket_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ defmodule Poxa.WebsocketHandler do
end
# Client Events
defp handle_pusher_event("client-" <> _event_name, decoded_json, req, %State{socket_id: socket_id} = state) do
event = PusherEvent.build_client_event(decoded_json, socket_id)
{:ok, event} = PusherEvent.build_client_event(decoded_json, socket_id)
channel = List.first(event.channels)
if Channel.private_or_presence?(channel) and Channel.subscribed?(channel, self) do
PusherEvent.publish(event)
Expand Down
22 changes: 11 additions & 11 deletions test/event_handler_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ defmodule Poxa.EventHandlerTest do
end

test "malformed_request with valid data" do
data = %{"name" => "", "data" => "", "channel" => ""}
event = %PusherEvent{}
expect(:cowboy_req, :body, 1, {:ok, :body, :req1})
expect(JSX, :decode, 1, {:ok, data})
expect(JSX, :decode, 1, {:ok, :data})
expect(PusherEvent, :build, [{[:data], {:ok, event}}])

assert malformed_request(:req, :state) == {false, :req1, %{body: :body, data: data}}
assert malformed_request(:req, :state) == {false, :req1, %{body: :body, event: event}}

assert validate :cowboy_req
assert validate JSX
Expand All @@ -34,10 +35,10 @@ defmodule Poxa.EventHandlerTest do
end

test "malformed_request with invalid data" do
data = %{"name" => "", "data" => ""}
expect(:cowboy_req, :body, 1, {:ok, :body, :req1})
expect(:cowboy_req, :set_resp_body, 2, :req2)
expect(JSX, :decode, 1, {:ok, data})
expect(JSX, :decode, 1, {:ok, :data})
expect(PusherEvent, :build, [{[:data], {:error, :reason}}])

assert malformed_request(:req, :state) == {true, :req2, :state}

Expand Down Expand Up @@ -71,28 +72,27 @@ defmodule Poxa.EventHandlerTest do
end

test "valid_entity_length with data key smaller than 10KB" do
json = %{"data" => "not10KB"}
assert valid_entity_length(:req, %{data: json}) == {true, :req, %{data: json}}
event = %PusherEvent{data: "not10KB"}
assert valid_entity_length(:req, %{event: event}) == {true, :req, %{event: event}}
end

test "valid_entity_length with data key bigger than 10KB" do
data = File.read! "test/more_than_10KB.data"
json = %{"data" => data}
event = %PusherEvent{data: data}
expect(:cowboy_req, :set_resp_body, 2, :req2)

assert valid_entity_length(:req, %{data: json}) == {false, :req2, %{data: json}}
assert valid_entity_length(:req, %{event: event}) == {false, :req2, %{event: event}}

assert validate :cowboy_req
end

test "post event" do
event = %PusherEvent{}
expect(PusherEvent, :build, 1, event)
expect(PusherEvent, :publish, [{[event], :ok}])
expect(Event, :notify, 2, :ok)
expect(:cowboy_req, :set_resp_body, 2, :req2)

assert post(:req, %{data: :data}) == {true, :req2, nil}
assert post(:req, %{event: event}) == {true, :req2, nil}

assert validate PusherEvent
assert validate :cowboy_req
Expand Down
29 changes: 29 additions & 0 deletions test/integration/trigger_event_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule Poxa.Integration.TriggerEvent do
use ExUnit.Case, async: true

@moduletag :integration

setup_all do
Application.ensure_all_started(:pusher)
Pusher.configure!("localhost", 8080, "app_id", "app_key", "secret")
:ok
end

test "trigger event returns 200" do
[channel, socket_id] = ["channel", "123.456"]

assert Pusher.trigger("test_event", %{}, channel, socket_id) == 200
end

test "trigger event returns 400 on invalid channel" do
[channel, socket_id] = ["channel:invalid", "123.456"]

assert Pusher.trigger("test_event", %{}, channel, socket_id) == 400
end

test "trigger event returns 400 on invalid socket_id" do
[channel, socket_id] = ["channel", "123456"]

assert Pusher.trigger("test_event", %{}, channel, socket_id) == 400
end
end
45 changes: 41 additions & 4 deletions test/pusher_event_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,59 @@ defmodule Poxa.PusherEventTest do
event = %{"channel" => "channel_name",
"data" => "event_data",
"name" => "event_etc"}
assert build(event) == %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name"]}
assert build(event) == {:ok, %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name"]}}
end

test "build PusherEvent with multiple channels" do
event = %{"channels" => ["channel_name1", "channel_name2"],
"data" => "event_data",
"name" => "event_etc"}
assert build(event) == %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name1","channel_name2"]}
assert build(event) == {:ok, %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name1","channel_name2"]}}
end

test "build PusherEvent with excluding socket_id" do
event = %{"channel" => "channel_name",
"data" => "event_data",
"socket_id" => "socketId",
"socket_id" => "123.456",
"name" => "event_etc"}
assert build(event) == %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name"], socket_id: "socketId"}
assert build(event) == {:ok, %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name"], socket_id: "123.456"}}
end

test "build PusherEvent with invalid socket_id" do
event = %{"channel" => "channel_name",
"data" => "event_data",
"socket_id" => "123:456",
"name" => "event_etc"}
assert build(event) == {:error, :invalid_event}
end

test "build PusherEvent with invalid channel name" do
event = %{"channel" => "channel:name",
"data" => "event_data",
"socket_id" => "123.456",
"name" => "event_etc"}
assert build(event) == {:error, :invalid_event}
end

test "build_client_event with excluding socket_id" do
event = %{"channel" => "channel_name",
"data" => "event_data",
"name" => "event_etc"}
assert build_client_event(event, "123.456") == {:ok, %PusherEvent{name: "event_etc", data: "event_data", channels: ["channel_name"], socket_id: "123.456"}}
end

test "build_client_event with invalid excluding socket_id" do
event = %{"channel" => "channel_name",
"data" => "event_data",
"name" => "event_etc"}
assert build_client_event(event, "123:456") == {:error, :invalid_event}
end

test "build_client_event with invalid channel name" do
event = %{"channel" => "channel:name",
"data" => "event_data",
"name" => "event_etc"}
assert build_client_event(event, "123.456") == {:error, :invalid_event}
end

test "sending message to a channel" do
Expand Down
8 changes: 4 additions & 4 deletions test/websocket_handler_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ defmodule Poxa.WebsocketHandlerTest do
decoded_json = %{"event" => "client-event"}
event = %PusherEvent{channels: ["presence-channel"], name: "client-event"}
expect(JSX, :decode!, [{[:client_event_json], decoded_json}])
expect(PusherEvent, :build_client_event, [{[decoded_json, :socket_id], event}])
expect(PusherEvent, :build_client_event, [{[decoded_json, :socket_id], {:ok, event}}])
expect(PusherEvent, :publish, 1, :ok)
expect(Channel, :subscribed?, 2, true)
expect(Event, :notify, [{[:client_event_message, %{socket_id: :socket_id, channels: ["presence-channel"], name: "client-event"}], :ok}])
Expand All @@ -231,7 +231,7 @@ defmodule Poxa.WebsocketHandlerTest do
decoded_json = %{"event" => "client-event"}
event = %PusherEvent{channels: ["private-channel"], name: "client-event"}
expect(JSX, :decode!, [{[:client_event_json], decoded_json}])
expect(PusherEvent, :build_client_event, [{[decoded_json, :socket_id], event}])
expect(PusherEvent, :build_client_event, [{[decoded_json, :socket_id], {:ok, event}}])
expect(PusherEvent, :publish, 1, :ok)
expect(Channel, :subscribed?, 2, true)
expect(Event, :notify, [{[:client_event_message, %{socket_id: :socket_id, channels: ["private-channel"], name: "client-event"}], :ok}])
Expand All @@ -251,7 +251,7 @@ defmodule Poxa.WebsocketHandlerTest do
decoded_json = %{"event" => "client-event"}
event = %PusherEvent{channels: ["private-not-subscribed"], name: "client-event"}
expect(JSX, :decode!, [{[:client_event_json], decoded_json}])
expect(PusherEvent, :build_client_event, [{[decoded_json, :socket_id], event}])
expect(PusherEvent, :build_client_event, [{[decoded_json, :socket_id], {:ok, event}}])
expect(Channel, :subscribed?, 2, false)

state = %State{socket_id: :socket_id}
Expand All @@ -268,7 +268,7 @@ defmodule Poxa.WebsocketHandlerTest do
test "client event on public channel" do
event = %PusherEvent{channels: ["public-channel"], name: "client-event"}
expect(JSX, :decode!, 1, %{"event" => "client-event"})
expect(PusherEvent, :build_client_event, 2, event)
expect(PusherEvent, :build_client_event, 2, {:ok, event})

state = %State{socket_id: :socket_id}

Expand Down

0 comments on commit 2c52a24

Please sign in to comment.