My Elxsy projects

I want to share my dev notes and journey with you all, this is in the order I remember them so might edit this post to tidy up later on.

This is not a “what you should do” piece, I try to stay away from stating my opinion on tech, more of what worked for me, and my mental notes as well as my workarounds. There might be better ones out there that I don’t know about, I am a newbie to the whole ecosystem.

Ecto:

I haven’t done anything complex with ecto this time that grants a note but all the time I ran on production with multiple branches and different migrations in them. When I came back to my main branch it was a relief to not have any DB migration conflicts on the actual DB since everything was done by timestamps on Ecto. Very pleased with that! Phew

Milligram CSS, bespoke CSS:

F that library.

Grab yourself some battle-tested and verified tools like bootstrap or Bulma likes, install NPM package, include into your scss and you are done.

SVG icons:

I was using inline SVG definitions from heroicons and taking a hit on the payloads, nope, retire that too. Get yourself fontawesome either via CDN or npm package.

Webpack:

At this point you might realize your visual UI, changes are not reflected in the code whatever you do, restarts, refresh, clear cache.

This is webpack being a little B.

Grab yourself this plugin, problems go away!


plugins: [
new MiniCssExtractPlugin({ filename: '../css/app.css' }),
new CleanWebpackPlugin(),
new CopyWebpackPlugin([{ from: 'static/', to: '../' }])
]

Showing MIX_ENV and version in the UI:

Very useful for techy devs knowing what branch, env and version they are dealing with on the server.

For this, you need to configure your config/config.exs

Find your main app config, add another atom :env


config :ex,
  ecto_repos: [Ex.Repo],
  env: Mix.env()

Then your template you can do


<%= Application.get_env(:ex, :env) %>:<%= Application.spec(:ex, :vsn) %>

Getting some unusual traffic, no idea what is going on. No IP in logs:

Add a plug. I am behind nginx so I set x-forwarded-for myself in the nginx and search for that.

defmodule ExWeb.Plugs.ClientIp do
  require Logger
  @behaviour Plug

  def init(opts), do: opts

  def call(conn, _opts) do
    Logger.metadata(client_ip: get_ip(conn))
    conn
  end

  # This code is from Plausible Analytics https://github.com/plausible/analytics/blob/3a1c9e67cd67d5cb1fec68a4dee34f8cd0e056fd/lib/plausible_web/remote_ip.ex
  def get_ip(conn) do
    forwarded_for = List.first(Plug.Conn.get_req_header(conn, "x-forwarded-for"))

    if forwarded_for do
      String.split(forwarded_for, ",")
      |> Enum.map(&String.trim/1)
      |> List.first()
    else
      to_string(:inet_parse.ntoa(conn.remote_ip))
    end
  end
end

in your endpoint.ex add the plug


plug ExWeb.Plugs.ClientIp

in your config.exs configure your logger to record ip

# Configures Elixir's Logger*
config :logger, :console,
  format: "$time $metadata[$level] $message\n",
  metadata: [:request_id, :client_ip]

That is definitely some dodgy BOT traffic:

Visit old friend https://www.abuseipdb.com/ community to log in to my account, report IPs, and batch download top 10K to block

Too many IPs to manage via Iptables:

Use ipset! https://confluence.jaytaala.com/display/TKB/Using+ipset+to+block+IP+addresses+-+firewall

Bots now get on the forms to spam, don’t want google snooping on users:

Come up with “finger”

Publish as a library, first elixir package and some new learning finger | Hex

Taking it a bit further Finger, a verification library to prove hommaannnnnness of a user - #17 by cenotaph

What is this 5 lines of phoenix vsn code in the logs?

Returns true if the socket is connected and the tracked static assets have changed. This function is useful to detect if the client is running on an outdated version of the marked static files. It works by comparing the static paths sent by the client with the one on the server.

My releases don’t work that way and don’t have live dependency stuff now. remove all the track-static from template.

I have tabs for budget and job hunt now. I want to select active items and set the necessary tabs when they are needed only.

Make a tab plug

defmodule ExWeb.Plugs.Tab do
  import Plug.Conn

  def init(default), do: default

  def call(conn, default) do
    assign(conn |> put_session(:ex_tabs, default), :ex_tabs, default)
  end
end

create a derived pipeline

 pipeline :jobhunt do
    plug :board
    plug ExWeb.Plugs.Tab, "_jobhunt_tabs.html"
  end

scope it so all the sub-resources get the tabs

  # job-hunt scope
  scope "/job-hunt/stuff", ExWeb do
    pipe_through :jobhunt

template rendering

 <%= if assigns[:ex_tabs] do %>
    <%= render assigns.ex_tabs, assigns %>
  <% end %>

Select active items in the menu and tabs based on url:

add to view helpers

def is_active?(%Plug.Conn{} = conn, section) when is_list(section) do
    if Enum.all?(section, &Enum.member?(conn.path_info, &1)), do: "is-active", else: ""
  end

  def is_active?(%Plug.Conn{} = conn, section) when is_binary(section) do
    if section in conn.path_info, do: "is-active", else: ""
  end

JS Date pickers do not work with liveview:

Try a workaround, post in forums, to investigate further Correct strategy for using datepicker attached to an input field with Liveview? - #11 by cenotaph

Fail2ban is great with abuseipdb:

But uses too much memory on my vps and will have to write custom jails for stuff. some manual labor will have to do for now.

Useful journal commands to spot issues and ban bots:

// Show all the activity since 8 hours who had 404 results and take 1 request before it. Usually, bots trying to poke holes

journalctl -u elxsy --since "8 hours ago" | grep "404" -B1

// Make shift mass banner since these are all dodgy urls no one should be visiting or posting to Wordpress, cancer of the internet!

journalctl -u elxsy --since "1 days ago" |
 grep  -E "wp-login|xmlrpc|wp-includes|actuator\/health|.env|logon.aspx" |
 grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' |
 while read -r ip ; do
        if [[ ! `ipset test blacklist $ip` ]] &>/dev/null; then
                echo -e "Added\t$ip"
                ipset add blacklist $ip &>/dev/null
        #else
        #       echo -e "Skipped\t$ip"
        fi
done
3 Likes