Skip to content

Instantly share code, notes, and snippets.

@cigzigwon
Last active May 13, 2022 17:56

Revisions

  1. cigzigwon revised this gist May 13, 2022. 1 changed file with 51 additions and 0 deletions.
    51 changes: 51 additions & 0 deletions oauth.livemd
    Original file line number Diff line number Diff line change
    @@ -67,3 +67,54 @@ end
    ```elixir
    Oauth.forge_oauth_head("GET", "https://pyroclasti.cloud", username: "cigzigwon")
    ```

    ```elixir
    ExUnit.start()
    ```

    ```elixir
    defmodule OauthTest do
    use ExUnit.Case

    @acct_id 6_789_973
    @customer_uri "https://#{@acct_id}.suitetalk.api.netsuite.com/services/rest/record/v1/customer"

    test "forge_sign/4 can return an oauth_signature using required header params" do
    timestamp = DateTime.utc_now() |> DateTime.to_unix() |> Integer.to_string()
    seed = :crypto.strong_rand_bytes(16) |> Base.encode16()
    nonce = :crypto.hash(:md5, seed) |> Base.encode16(case: :lower) |> String.slice(0..12)

    oauth_signature =
    Oauth.forge_sign(
    "POST&#{@customer_uri |> URI.encode_www_form()}",
    timestamp,
    nonce,
    []
    )

    assert oauth_signature |> String.length() >= 46
    end

    test "forge_sign/4 can return an oauth_signature using qs params" do
    timestamp = DateTime.utc_now() |> DateTime.to_unix() |> Integer.to_string()
    seed = :crypto.strong_rand_bytes(16) |> Base.encode16()
    nonce = :crypto.hash(:md5, seed) |> Base.encode16(case: :lower) |> String.slice(0..12)

    oauth_signature =
    Oauth.forge_sign(
    "POST&#{@customer_uri |> URI.encode_www_form()}",
    timestamp,
    nonce,
    username: "cigzigwon"
    )

    assert oauth_signature |> String.length() >= 46
    end

    test "forge_oauth_head/3 can return an Authorization tuple header for OAuth 1.0a" do
    {"Authorization", value} = Oauth.forge_oauth_head("POST", @customer_uri)
    assert value |> String.contains?("oauth_consumer_secret") == false
    assert value |> String.contains?("oauth_token_secret") == false
    end
    end
    ```
  2. cigzigwon created this gist May 13, 2022.
    69 changes: 69 additions & 0 deletions oauth.livemd
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    # Oauth Keyforge Test

    ## Oauth Module

    ```elixir
    defmodule Oauth do
    # 6789973 Acct# for NetSuite Support
    @acct_id 6_789_973
    @base_uri "https://#{@acct_id}.suitetalk.api.netsuite.com/services/rest/record/v1/"
    @oauth_creds [
    realm: "#{@acct_id}",
    oauth_consumer_key: "1a1a4402b8a1dd876e67352e12b1a94ba6c5620f15d349f101b0059c13ecf030",
    oauth_consumer_secret: "949462be662ece983c8cf8a79e96c0901d2d8d2efd584f4c82ba9ab5c4ad3c8b",
    oauth_token: "df92b02bffec93f03c0f3454437cd5115efad796da37e90321f4ea02732d59e2",
    oauth_token_secret: "db60928d4387dabc626d23ce01fa5b68c19fd645871b35ba925608052d65262c",
    oauth_signature_method: "HMAC-SHA256",
    oauth_version: "1.0"
    ]

    def forge_oauth_head(method, url, qs \\ []) do
    timestamp = DateTime.utc_now() |> DateTime.to_unix() |> Integer.to_string()
    seed = :crypto.strong_rand_bytes(16) |> Base.encode16()
    nonce = :crypto.hash(:md5, seed) |> Base.encode16(case: :lower) |> String.slice(0..12)

    head =
    (@oauth_creds ++ [oauth_timestamp: timestamp, oauth_nonce: nonce])
    |> Enum.reject(fn {key, _} ->
    [:oauth_consumer_secret, :oauth_token_secret] |> Enum.member?(key)
    end)
    |> Enum.reduce([], fn {key, value}, acc ->
    acc ++ ["#{key}=\"#{value |> URI.encode_www_form()}\""]
    end)
    |> Enum.join(",")

    {"Authorization",
    "OAuth #{head}" <>
    ",oauth_signature=\"" <>
    forge_sign(method <> "&" <> (url |> URI.encode_www_form()), timestamp, nonce, qs) <> "\""}
    end

    def forge_sign(head, timestamp, nonce, qs) do
    params =
    (@oauth_creds ++ [oauth_timestamp: timestamp, oauth_nonce: nonce] ++ qs)
    |> Enum.reject(fn {key, _} ->
    [:realm, :oauth_consumer_secret, :oauth_token_secret] |> Enum.member?(key)
    end)
    |> Enum.sort_by(fn {key, val} ->
    {key, val}
    end)
    |> Enum.reduce([], fn {key, value}, acc ->
    acc ++ ["#{key}=#{value |> URI.encode(&URI.char_unreserved?(&1))}"]
    end)
    |> Enum.join("&")
    |> URI.encode_www_form()

    key =
    (@oauth_creds |> Keyword.fetch!(:oauth_consumer_secret)) <>
    "&" <> (@oauth_creds |> Keyword.fetch!(:oauth_token_secret))

    :crypto.mac(:hmac, :sha256, key, head <> "&" <> params)
    |> Base.encode64(case: :lower)
    |> URI.encode_www_form()
    end
    end
    ```

    ```elixir
    Oauth.forge_oauth_head("GET", "https://pyroclasti.cloud", username: "cigzigwon")
    ```