Add json wrapper

pull/564/head
connor rigby 2018-06-11 15:57:34 -07:00
parent 0f88f579e0
commit 091f13d834
No known key found for this signature in database
GPG Key ID: 24DC438382965C3B
10 changed files with 71 additions and 10 deletions

View File

@ -44,7 +44,8 @@ config :farmbot, :behaviour,
authorization: Farmbot.Bootstrap.Authorization,
firmware_handler: Farmbot.Firmware.StubHandler,
http_adapter: Farmbot.HTTP.HTTPoisonAdapter,
gpio_handler: Farmbot.System.GPIO.StubHandler
gpio_handler: Farmbot.System.GPIO.StubHandler,
json_parser: Farmbot.JSON.JasonParser
config :farmbot, :farmware,
first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"

View File

@ -9,3 +9,5 @@ lib/farmbot/system/gpio/gpio.ex
lib/farmbot/asset/farm_event.ex
lib/farmbot/asset/regimen.ex
lib/farmbot/jwt.ex
lib/farmbot/json/jason_parser.ex
lib/farmbot/json/parser.ex

View File

@ -0,0 +1,10 @@
defmodule Farmbot.JSON.JasonParser do
@moduledoc "Parser handler for Jason"
@behaviour Farmbot.JSON.Parser
def decode(data), do: Jason.decode(data)
def encode(data), do: Jason.encode(data)
require Protocol
Protocol.derive(Jason.Encoder, Farmbot.Jwt)
end

View File

@ -0,0 +1,25 @@
defmodule Farmbot.JSON do
@moduledoc "Wraps a dependency for easy upgrade and no vendor lock."
@parser Application.get_env(:farmbot, :behaviour)[:json_parser]
@parser || Mix.raise("Unconfigured JSON Parser.")
@spec decode(iodata) :: {:ok, term} | {:error, term}
def decode(iodata), do: @parser.decode(iodata)
@spec encode(term) :: {:ok, term} | {:error, term}
def encode(data), do: @parser.encode(data)
def decode!(iodata) do
case decode(iodata) do
{:ok, results} -> results
{:error, reason} -> raise(reason)
end
end
def encode!(data) do
case encode(data) do
{:ok, results} -> results
{:error, reason} -> raise(reason)
end
end
end

View File

@ -0,0 +1,7 @@
defmodule Farmbot.JSON.Parser do
@moduledoc """
Callback module for wrapping a json dependency.
"""
@callback decode(iodata) :: {:ok, term} | {:error, term}
@callback encode(term) :: {:ok, iodata} | {:error, term}
end

View File

@ -29,11 +29,12 @@ defmodule Farmbot.Jwt do
body = tkn |> String.split(".") |> Enum.at(1)
with {:ok, json} <- Base.decode64(body, padding: false),
{:ok, jwt} <- Poison.decode(json, as: %__MODULE__{}) do
{:ok, data} <- Farmbot.JSON.decode(json),
{:ok, jwt} <- decode_map(data) do
{:ok, jwt}
else
:error -> {:error, :base64_decode_fail}
{:error, :invalid, _} -> {:error, :json_decode_error}
:error -> {:error, "base64_decode_fail"}
{:error, _resson} -> {:error, "json_decode_error"}
end
end
@ -45,4 +46,18 @@ defmodule Farmbot.Jwt do
{:error, reason} -> raise(reason)
end
end
defp decode_map(%{} = map) do
{:ok,
struct(
Farmbot.Jwt,
bot: map["bot"],
exp: map["exp"],
iss: map["iss"],
mqtt: map["mqtt"],
os_update_server: map["os_update_server"],
vhost: map["vhost"],
interim_email: map["interim_email"]
)}
end
end

View File

@ -5,7 +5,6 @@ defmodule Mix.Tasks.Farmbot.Firmware.Slack do
use Mix.Task
import Mix.Tasks.Farmbot.Env
@dialyzer {[:no_return], [run: 1]}
def run(opts) do
token = slack_token()

View File

@ -102,6 +102,7 @@ defmodule Farmbot.Mixfile do
{:gen_stage, "~> 0.12"},
{:phoenix_html, "~> 2.10.5"},
{:poison, "~> 3.1.0"},
{:jason, "~> 1.0"},
{:httpoison, "~> 1.1"},
{:jsx, "~> 2.8.0"},
{:timex, "~> 3.3"},

View File

@ -14,7 +14,7 @@
"credo": {:hex, :credo, "0.9.1", "f021affa11b32a94dc2e807a6472ce0914289c9132f99644a97fc84432b202a1", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:poison, ">= 0.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.4.1", "ad9e501edf7322f122f7fc151cce7c2a0c9ada96f2b0155b8a09a795c2029770", [:mix], [], "hexpm"},
"dialyxir": {:git, "https://github.com/jeremyjh/dialyxir.git", "292191fdb71a10827e7088d01d9ba16461e40369", []},
"dialyxir": {:git, "https://github.com/jeremyjh/dialyxir.git", "fa821b418b5e7c54ca7a2f184d55b5310693457c", []},
"distillery": {:hex, :distillery, "1.5.2", "eec18b2d37b55b0bcb670cf2bcf64228ed38ce8b046bb30a9b636a6f5a4c0080", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.8", "a4463c0928b970f2cee722cd29aaac154e866a15882c5737e0038bbfcf03ec2c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
@ -32,6 +32,7 @@
"httpoison": {:hex, :httpoison, "1.1.1", "96ed7ab79f78a31081bb523eefec205fd2900a02cda6dbc2300e7a1226219566", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "5.1.1", "cbc3b2fa1645113267cc59c760bafa64b2ea0334635ef06dbac8801e42f7279c", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"inch_ex": {:hex, :inch_ex, "0.5.6", "418357418a553baa6d04eccd1b44171936817db61f4c0840112b420b8e378e67", [:mix], [{:poison, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"joken": {:hex, :joken, "1.5.0", "42a0953e80bd933fc98a0874e156771f78bf0e92abe6c3a9c22feb6da28efb0b", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"},
"jose": {:hex, :jose, "1.8.4", "7946d1e5c03a76ac9ef42a6e6a20001d35987afd68c2107bcd8f01a84e75aa73", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"},
"jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], [], "hexpm"},

View File

@ -30,7 +30,7 @@ defmodule Farmbot.JwtTest do
tkn = [head, "not_a_valid_token", foot] |> Enum.join(".")
r = Jwt.decode(tkn)
refute match?({:ok, _}, r)
assert r == :error
assert r == {:error, "base64_decode_fail"}
end
test "Gives Poison Error when it can't be decoded as json", %{token: tkn} do
@ -39,14 +39,14 @@ defmodule Farmbot.JwtTest do
tkn = [head, not_token, foot] |> Enum.join(".")
r = Jwt.decode(tkn)
refute match?({:ok, _}, r)
assert r == {:error, {:invalid, "h", 0}}
assert r == {:error, "json_decode_error"}
end
test "raises on bad token because base64", %{token: tkn} do
[head, _body, foot] = String.split(tkn, ".")
tkn = [head, "not_a_valid_token", foot] |> Enum.join(".")
assert_raise RuntimeError, "Failed to base64 decode.", fn ->
assert_raise RuntimeError, "base64_decode_fail", fn ->
Jwt.decode!(tkn)
end
end
@ -56,7 +56,7 @@ defmodule Farmbot.JwtTest do
not_token = Base.encode64("hello world", padding: false)
tkn = [head, not_token, foot] |> Enum.join(".")
assert_raise RuntimeError, "Failed to json decode.", fn ->
assert_raise RuntimeError, "json_decode_error", fn ->
Jwt.decode!(tkn)
end
end