Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use with liveview socket #36

Closed
xpressivecode opened this issue Oct 19, 2024 · 5 comments
Closed

How to use with liveview socket #36

xpressivecode opened this issue Oct 19, 2024 · 5 comments

Comments

@xpressivecode
Copy link

I've added the plug, but I'm unsure how to access the remote_ip from a liveview socket?

So for now I've settled on the following

    headers = get_connect_info(socket, :x_headers)
    remote_ip = RemoteIp.from(headers) || "unknown"

    remote_ip =
      case remote_ip do
        {_, _, _, _} -> remote_ip |> :inet.ntoa() |> to_string() |> String.trim()
        _ -> "unknown"
      end

      socket = socket |> assign(:remote_ip, remote_ip) |> ...

Is there a better implementation pattern?

Thanks either way, this lib helped a lot.

@ajvondrak
Copy link
Owner

ajvondrak commented Oct 19, 2024

Disclaimer: I've never used Phoenix.

But as far as I understand, yes, outside of the Plug pipeline you have to manually call RemoteIp.from/2 yourself on a list of headers, then do whatever you want with that (in your case, transforming it into a string and assigning it on the socket). Last I checked, sockets only have the option to expose x- headers and not others, so if you're using something like X-Forwarded-For and not (say) Fly-Client-IP (cf. #30 (comment)), then the forwarded IP should be available from the socket's connect info. This is the basis of the sketched out connect/3 handler in https://hexdocs.pm/remote_ip/RemoteIp.html#module-usage. I also once went spelunking through some implementation details that I captured here, fwiw: #32 (comment). So as long as your implementation seems to be working, I think that you're using RemoteIp.from/2 as intended. 👍

Glad this little library helped!

@xpressivecode
Copy link
Author

Ok great. Appreciate the library and feedback. It works great while hosting our app on Gigalixir.

@ajvondrak
Copy link
Owner

@xpressivecode A bit of drive-by code review I thought of while walking my dog. 😅 While calling RemoteIp.from/2 is correct, I do think your implementation has a subtle issue. Since you put the || "unknown" on the result, it kinda forces you into the wordy case spelling to match against "IP returned" vs "no IP found". But your case will actually fail to match an IPv6 address (a tuple with 8 elements), instead wildcarding it away into another "unknown".

So I think it'd be simpler to use the nil return value of RemoteIp.from/2 and avoid pattern matching anything downstream. Something along the lines of this (untested):

headers = get_connect_info(socket, :x_headers)
remote_ip = RemoteIp.from(headers)

human_friendly_remote_ip =
  if remote_ip do
    :inet.ntoa(remote_ip) |> to_string()
  else
    "unknown"
  end

socket = socket |> assign(:remote_ip, human_friendly_remote_ip)

Figured I should mention it just in case. :)

@xpressivecode
Copy link
Author

@ajvondrak I'm really sorry. I saw the notification come in, meant to reply and things kicked off at work. I really appreciate you taking the added time to follow up and provide a better solution.

We'll be updating to use this implementation.

@ajvondrak
Copy link
Owner

@xpressivecode No worries, I know how that goes! Glad I could help either way. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants