Add json wrapper
parent
0f88f579e0
commit
091f13d834
|
@ -44,7 +44,8 @@ config :farmbot, :behaviour,
|
||||||
authorization: Farmbot.Bootstrap.Authorization,
|
authorization: Farmbot.Bootstrap.Authorization,
|
||||||
firmware_handler: Farmbot.Firmware.StubHandler,
|
firmware_handler: Farmbot.Firmware.StubHandler,
|
||||||
http_adapter: Farmbot.HTTP.HTTPoisonAdapter,
|
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,
|
config :farmbot, :farmware,
|
||||||
first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
|
first_part_farmware_manifest_url: "https://raw.githubusercontent.com/FarmBot-Labs/farmware_manifests/master/manifest.json"
|
||||||
|
|
|
@ -9,3 +9,5 @@ lib/farmbot/system/gpio/gpio.ex
|
||||||
lib/farmbot/asset/farm_event.ex
|
lib/farmbot/asset/farm_event.ex
|
||||||
lib/farmbot/asset/regimen.ex
|
lib/farmbot/asset/regimen.ex
|
||||||
lib/farmbot/jwt.ex
|
lib/farmbot/jwt.ex
|
||||||
|
lib/farmbot/json/jason_parser.ex
|
||||||
|
lib/farmbot/json/parser.ex
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -29,11 +29,12 @@ defmodule Farmbot.Jwt do
|
||||||
body = tkn |> String.split(".") |> Enum.at(1)
|
body = tkn |> String.split(".") |> Enum.at(1)
|
||||||
|
|
||||||
with {:ok, json} <- Base.decode64(body, padding: false),
|
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}
|
{:ok, jwt}
|
||||||
else
|
else
|
||||||
:error -> {:error, :base64_decode_fail}
|
:error -> {:error, "base64_decode_fail"}
|
||||||
{:error, :invalid, _} -> {:error, :json_decode_error}
|
{:error, _resson} -> {:error, "json_decode_error"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,4 +46,18 @@ defmodule Farmbot.Jwt do
|
||||||
{:error, reason} -> raise(reason)
|
{:error, reason} -> raise(reason)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -5,7 +5,6 @@ defmodule Mix.Tasks.Farmbot.Firmware.Slack do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Mix.Tasks.Farmbot.Env
|
import Mix.Tasks.Farmbot.Env
|
||||||
|
|
||||||
@dialyzer {[:no_return], [run: 1]}
|
|
||||||
def run(opts) do
|
def run(opts) do
|
||||||
token = slack_token()
|
token = slack_token()
|
||||||
|
|
||||||
|
|
1
mix.exs
1
mix.exs
|
@ -102,6 +102,7 @@ defmodule Farmbot.Mixfile do
|
||||||
{:gen_stage, "~> 0.12"},
|
{:gen_stage, "~> 0.12"},
|
||||||
{:phoenix_html, "~> 2.10.5"},
|
{:phoenix_html, "~> 2.10.5"},
|
||||||
{:poison, "~> 3.1.0"},
|
{:poison, "~> 3.1.0"},
|
||||||
|
{:jason, "~> 1.0"},
|
||||||
{:httpoison, "~> 1.1"},
|
{:httpoison, "~> 1.1"},
|
||||||
{:jsx, "~> 2.8.0"},
|
{:jsx, "~> 2.8.0"},
|
||||||
{:timex, "~> 3.3"},
|
{:timex, "~> 3.3"},
|
||||||
|
|
|
@ -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"},
|
"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"},
|
"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"},
|
"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"},
|
"distillery": {:hex, :distillery, "1.5.2", "eec18b2d37b55b0bcb670cf2bcf64228ed38ce8b046bb30a9b636a6f5a4c0080", [:mix], [], "hexpm"},
|
||||||
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [: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"},
|
"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"},
|
"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"},
|
"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"},
|
"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"},
|
"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"},
|
"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"},
|
"jsx": {:hex, :jsx, "2.8.2", "7acc7d785b5abe8a6e9adbde926a24e481f29956dd8b4df49e3e4e7bcc92a018", [:mix, :rebar3], [], "hexpm"},
|
||||||
|
|
|
@ -30,7 +30,7 @@ defmodule Farmbot.JwtTest do
|
||||||
tkn = [head, "not_a_valid_token", foot] |> Enum.join(".")
|
tkn = [head, "not_a_valid_token", foot] |> Enum.join(".")
|
||||||
r = Jwt.decode(tkn)
|
r = Jwt.decode(tkn)
|
||||||
refute match?({:ok, _}, r)
|
refute match?({:ok, _}, r)
|
||||||
assert r == :error
|
assert r == {:error, "base64_decode_fail"}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Gives Poison Error when it can't be decoded as json", %{token: tkn} do
|
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(".")
|
tkn = [head, not_token, foot] |> Enum.join(".")
|
||||||
r = Jwt.decode(tkn)
|
r = Jwt.decode(tkn)
|
||||||
refute match?({:ok, _}, r)
|
refute match?({:ok, _}, r)
|
||||||
assert r == {:error, {:invalid, "h", 0}}
|
assert r == {:error, "json_decode_error"}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "raises on bad token because base64", %{token: tkn} do
|
test "raises on bad token because base64", %{token: tkn} do
|
||||||
[head, _body, foot] = String.split(tkn, ".")
|
[head, _body, foot] = String.split(tkn, ".")
|
||||||
tkn = [head, "not_a_valid_token", foot] |> Enum.join(".")
|
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)
|
Jwt.decode!(tkn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -56,7 +56,7 @@ defmodule Farmbot.JwtTest do
|
||||||
not_token = Base.encode64("hello world", padding: false)
|
not_token = Base.encode64("hello world", padding: false)
|
||||||
tkn = [head, not_token, foot] |> Enum.join(".")
|
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)
|
Jwt.decode!(tkn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue