add function comments and throw on unmatched decode attempts

This commit is contained in:
glyph 2022-09-23 10:31:05 +01:00
parent 7c92c57ed2
commit 0f1827f24b
4 changed files with 138 additions and 58 deletions

View File

@ -1,21 +1,10 @@
defmodule SsbBfe do
@moduledoc """
Documentation for `SsbBfe`.
Binary Field Encodings (BFE) for Secure Scuttlebutt (SSB).
Encode and decode TFD values.
"""
@doc """
Hello world.
## Examples
iex> SsbBfe.hello()
:world
"""
def hello do
:world
end
# ENCODE
def encode(value) when is_list(value) do
@ -89,8 +78,8 @@ defmodule SsbBfe do
6 == first_byte ->
SsbBfe.Decoder.decode_generic(value)
nil ->
true
true ->
nil
end
end

View File

@ -1,75 +1,118 @@
defmodule SsbBfe.Decoder do
# Split the TF tag from the data bytes and base64 encode them.
defp extract_base64_data(bin, tf_tag) do
[_, base64_data] = :binary.split(bin, tf_tag)
Base.encode64(base64_data)
end
def decode_blob(blob) do
encoded_base64_data = extract_base64_data(blob, <<2, 0>>)
@doc """
Take a blob ID as an encoded binary, extract and encode the base64 data and return the dedoded string representing the TFD.
"""
def decode_blob(blob_id) do
encoded_base64_data = extract_base64_data(blob_id, <<2, 0>>)
"&" <> encoded_base64_data <> ".sha256"
end
@doc """
Take an encrypted box as an encoded binary, extract the TF tag and call the appropriate decoder.
"""
def decode_box(box) do
tf_tag = binary_part(box, 0, 2)
decode_box(box, tf_tag)
end
# Matches box.
@doc """
Take an encrypted box as an encoded binary and the TF tag of a box, extract and encode the base64 data and return the dedoded string representing the TFD.
"""
def decode_box(box, <<5, 0>>) do
encoded_base64_data = extract_base64_data(box, <<5, 0>>)
encoded_base64_data <> ".box"
end
# Matches box2.
@doc """
Take an encrypted box as an encoded binary and the TF tag of a box2, extract and encode the base64 data and return the dedoded string representing the TFD.
"""
def decode_box(box, <<5, 1>>) do
encoded_base64_data = extract_base64_data(box, <<5, 1>>)
encoded_base64_data <> ".box2"
end
def decode_feed(feed) do
tf_tag = binary_part(feed, 0, 2)
decode_feed(feed, tf_tag)
@doc """
Take a feed ID as an encoded binary, extract the TF tag and call the appropriate decoder.
"""
def decode_feed(feed_id) do
tf_tag = binary_part(feed_id, 0, 2)
decode_feed(feed_id, tf_tag)
end
# Matches classic feed.
def decode_feed(feed, <<0, 0>>) do
encoded_base64_data = extract_base64_data(feed, <<0, 0>>)
@doc """
Take a feed ID as an encoded binary and the TF tag of a classic feed, extract and encode the base64 data and return the dedoded string representing the TFD.
"""
def decode_feed(feed_id, <<0, 0>>) do
encoded_base64_data = extract_base64_data(feed_id, <<0, 0>>)
"@" <> encoded_base64_data <> ".ed25519"
end
@doc """
Take a boolean `true` value as an encoded binary and return `true`.
"""
def decode_generic(<<6, 1, 1>>), do: true
@doc """
Take a boolean `false` value as an encoded binary and return `false`.
"""
def decode_generic(<<6, 1, 0>>), do: false
@doc """
Take a `nil` value as an encoded binary and return `nil`.
"""
def decode_generic(<<6, 2>>), do: nil
@doc """
Take a generic value as an encoded binary, extract the TF tag and call the appropriate decoder.
"""
def decode_generic(generic) do
tf_tag = binary_part(generic, 0, 2)
decode_generic(generic, tf_tag)
end
# Matches generic string.
@doc """
Take a generic string as an encoded binary and the TF tag of a generic string, extract the bytes representing the string data and return the decoded string.
"""
def decode_generic(str, <<6, 0>>) do
[_, str_data] = :binary.split(str, <<6, 0>>)
str_data
end
# Matches generic bytes.
def decode_generic(bytes, <<6, 3>>), do: bytes
def decode_msg(msg) do
tf_tag = binary_part(msg, 0, 2)
decode_msg(msg, tf_tag)
@doc """
Take generic bytes as an encoded binary and the TF tag of generic bytes, extract the bytes representing the data and return them.
"""
def decode_generic(bytes, <<6, 3>>) do
[_, bytes] = :binary.split(bytes, <<6, 3>>)
bytes
end
# Matches classic message.
def decode_msg(msg, <<1, 0>>) do
encoded_base64_data = extract_base64_data(msg, <<1, 0>>)
@doc """
Take a message ID as an encoded binary, extract the TF tag and call the appropriate decoder.
"""
def decode_msg(msg_id) do
tf_tag = binary_part(msg_id, 0, 2)
decode_msg(msg_id, tf_tag)
end
@doc """
Take a message ID as an encoded binary and the TF tag of a classic message, extract and encode the base64 data and return the dedoded string representing the TFD.
"""
def decode_msg(msg_id, <<1, 0>>) do
encoded_base64_data = extract_base64_data(msg_id, <<1, 0>>)
"%" <> encoded_base64_data <> ".sha256"
end
def decode_sig(sig) do
encoded_base64_data = extract_base64_data(sig, <<4, 0>>)
@doc """
Take a signature ID as an encoded binary, extract and encode the base64 data and return the dedoded string representing the TFD.
"""
def decode_sig(sig_id) do
encoded_base64_data = extract_base64_data(sig_id, <<4, 0>>)
encoded_base64_data <> ".sig.ed25519"
end
end

View File

@ -11,42 +11,68 @@ defmodule SsbBfe.Encoder do
Base.decode64(base64_data)
end
@doc """
Take a blob ID as a string, match on the type-format tag, extract and decode the base64 data and return the encoded bytes representing the TFD.
"""
def encode_blob(blob_id) do
blob_tf_tag = SsbBfe.Types.get_blob_type(blob_id)
{:ok, decoded_base64_data} = extract_base64_data(blob_id)
blob_tf_tag <> decoded_base64_data
end
@doc """
Take a boolean `true` value and return the encoded bytes representing the TFD.
"""
def encode_bool(true), do: <<6, 1, 1>>
@doc """
Take a boolean `false` value and return the encoded bytes representing the TFD.
"""
def encode_bool(false), do: <<6, 1, 0>>
@doc """
Take an encrypted box as a string, match on the type-format tag, extract and decode the base64 data and return the encoded bytes representing the TFD.
"""
def encode_box(box_str) do
box_tf_tag = SsbBfe.Types.get_box_type(box_str)
{:ok, decoded_base64_data} = extract_base64_data(box_str, ".")
box_tf_tag <> decoded_base64_data
end
@doc """
Take a feed ID as a string, match on the type-format tag, extract and decode the base64 data and return the encoded bytes representing the TFD.
"""
def encode_feed(feed_id) do
feed_tf_tag = SsbBfe.Types.get_feed_type(feed_id)
{:ok, decoded_base64_data} = extract_base64_data(feed_id)
feed_tf_tag <> decoded_base64_data
end
@doc """
Take a message ID as a string, match on the type-format tag, extract and decode the base64 data and return the encoded bytes representing the TFD.
"""
def encode_msg(msg_id) do
msg_tf_tag = SsbBfe.Types.get_msg_type(msg_id)
{:ok, decoded_base64_data} = extract_base64_data(msg_id)
msg_tf_tag <> decoded_base64_data
end
@doc """
Take a `nil` value and return the encoded bytes representing the TFD.
"""
def encode_nil(), do: <<6, 2>>
def encode_sig(sig) do
{:ok, decoded_base64_data} = extract_base64_data(sig, ".sig.ed25519")
<<4, 0>> <> decoded_base64_data
@doc """
Take a signature ID as a string, match on the type-format tag, extract and decode the base64 data and return the encoded bytes representing the TFD.
"""
def encode_sig(sig_id) do
sig_tf_tag = SsbBfe.Types.get_sig_type(sig_id)
{:ok, decoded_base64_data} = extract_base64_data(sig_id, ".sig.ed25519")
sig_tf_tag <> decoded_base64_data
end
def encode_str(str), do: <<6, 0>> <> str
# def encode_uri(uri)
@doc """
Take a string value and return the encoded bytes representing the TFD.
"""
def encode_str(str), do: <<6, 0>> <> str
end

View File

@ -1,17 +1,21 @@
defmodule SsbBfe.Types do
@doc ~S"""
@doc """
Take a blob ID as a string and return the encoded bytes representing the blob
type-format. Return `nil` if the ID does not end with `.sha256`.
type-format. Throw an error if the ID does not end with `.sha256`.
"""
def get_blob_type(blob_id) do
if String.ends_with?(blob_id, ".sha256") do
<<2, 0>>
cond do
String.ends_with?(blob_id, ".sha256") ->
<<2, 0>>
true ->
throw({:unknown_format, blob_id})
end
end
@doc ~S"""
@doc """
Take a box as a string and return the encoded bytes representing the box
type-format. Return `nil` if the ID does not end with `.box` or `.box2`.
type-format. Throw an error if the ID does not end with `.box` or `.box2`.
"""
def get_box_type(boxed_str) do
cond do
@ -22,23 +26,27 @@ defmodule SsbBfe.Types do
<<5, 1>>
true ->
nil
throw({:unknown_format, boxed_str})
end
end
@doc ~S"""
@doc """
Take a feed ID (key) as a string and return the encoded bytes representing
the feed type-format. Return `nil` if the ID does not end with `.ed25519`.
the feed type-format. Throw an error if the ID does not end with `.ed25519`.
"""
def get_feed_type(feed_id) do
if String.ends_with?(feed_id, ".ed25519") do
<<0, 0>>
cond do
String.ends_with?(feed_id, ".ed25519") ->
<<0, 0>>
true ->
throw({:unknown_format, feed_id})
end
end
@doc ~S"""
@doc """
Take a message ID as a string and return the encoded bytes representing
the message type-format. Return `nil` if the ID does not end with `.sha256`
the message type-format. Throw an error if the ID does not end with `.sha256`
or `.cloaked`.
"""
def get_msg_type(msg_id) do
@ -50,7 +58,21 @@ defmodule SsbBfe.Types do
<<1, 2>>
true ->
nil
throw({:unknown_format, msg_id})
end
end
@doc """
Take a signature ID as a string and return the encoded bytes representing
the signature type-format. Throw an error if the ID does not end with `.sig.ed25519`.
"""
def get_sig_type(sig_id) do
cond do
String.ends_with?(sig_id, ".sig.ed25519") ->
<<4, 0>>
true ->
throw({:unknown_format, sig_id})
end
end
end