defmodule Nostrum.Token do @moduledoc """ A helper module for verifying the Discord bot token. The token can be generated in the "Bot" tab of your Application the [Discord Developer Portal](https://discord.com/developers/applications) and can be configured in your config file. ```elixir config :nostrum, token: "666" # The token of your bot as a string ``` """ @invalid_token_error_message ~S[Invalid token format. Copy it again from the "Bot" tab of your Application in the Discord Developer Portal.] @no_token_error_message "A bot token needs to be supplied in your config file" @doc """ Checks if the Discord bot token has the correct format. We check if the token is a binary followed by splitting it into 3 parts separated by a dot `"."`. The first part is the Base64 encoded user_id which we decode and parse into as integer. The second part is an encoded timestamp, and the last part an arbitrary cryptographic signature. Raises on failure. ## Examples iex> token = "OTY4NTU2MzQ4MzkwMzkxODU5.G49NjP.pD8PLpKp-Xx8sr-8m1DCxSPTJZdcpcJZOExc1c" iex> Nostrum.Token.check_token!(token) :ok iex> token = "ODY4MDcxODUzMDMyMzU3OTc4.YPqU6Q.jNJcq1daGG3otexX3c1LcxCpgpQ" iex> Nostrum.Token.check_token!(token) :ok """ def check_token!, do: check_token!(Application.get_env(:nostrum, :token)) def check_token!(nil), do: raise(@no_token_error_message) def check_token!(<>) do decode_user_id!(user_id) end def check_token!(token) when is_binary(token) do case String.split(token, ".") do [user_id, _timestamp, _hmac_auth] -> decode_user_id!(user_id) _ -> raise(@invalid_token_error_message) end end defp decode_user_id!(user_id) do _user_id = user_id |> Base.decode64!(padding: false) |> String.to_integer() :ok rescue exception -> reraise( RuntimeError, [message: @invalid_token_error_message, exception: exception], __STACKTRACE__ ) end end