<FromGitter>
<ZeroPointEnergy> @Blacksmoke16 This is awesome, thanks.
feepbot has quit [Ping timeout: 240 seconds]
feepbot has joined #amber
<FromGitter>
<Blacksmoke16> np:p
feepbot has quit [Ping timeout: 240 seconds]
feepbot has joined #amber
wontruefree has joined #amber
wontruefree has quit [Client Quit]
wontruefree has joined #amber
_whitelogger has joined #amber
<FromGitter>
<ZeroPointEnergy> Is it a horrible idea to additional cli stuff (like import/maintenance functions) directly into the same application binary as the web-application?
<robacarp>
it's not a horrible idea, but I found the maintenance overhead to be much less just creating additional binaries
<FromGitter>
<Prutheus> @robacarp how does it work with nginx together?
<robacarp>
you can be lazy and require the entire application into each binary, or you can be really precise and only require what you want
<robacarp>
@prutheus, I assume you're talking about the client ip address?
<FromGitter>
<Prutheus> yeah
<FromGitter>
<ZeroPointEnergy> @robacarp yeah, currently I have it separated, but was wondering if there is an issue if I integrate it. But will probably leave it separated for now
<robacarp>
@prutheus however, doing any sort of authentication or validation on client ip address is risky because the X-Forwarded-For header can be spoofed, ip addresses can be spoofed, users can connect via tor or proxies, etc
<FromGitter>
<Prutheus> do you have also a link how to put amber behind nginx?
<FromGitter>
<Prutheus> I just need it for ip registration block
<robacarp>
@zeropointenergy it would make your compile time faster because the compiler doesn't have to run once for each binary, but I don't think it matters. I run `shards build --production` (or something like that) and it builds everything in < a minute
<robacarp>
again, guarding registrations against ip address is not secure
<FromGitter>
<Prutheus> and how should i do it otherwise?
<robacarp>
if you want to white list who can register and who cannot, I recommend using something like invitation codes/links or manual account approval
<FromGitter>
<elorest> I'd run it behind nginx very similar to running rails with puma.
<FromGitter>
<Prutheus> yeah the problem is i want to realize ip block in case a user does some trash and i need to ban him
<FromGitter>
<elorest> @Prutheus Depending on what your doing though you don't necessarily have to run it behind nginx.
<FromGitter>
<elorest> Ok.
<FromGitter>
<Prutheus> @elorest i need to be able to block users by their ip
<robacarp>
so they'll run an ip hide, vpn, tor, etc and just sign up again?
<FromGitter>
<Prutheus> yeah, but how else should i realize it?
<robacarp>
ip addresses are not tied to physical addresses
<FromGitter>
<Prutheus> but any other idea?
<robacarp>
moreover, what if you have someone from a large private network like a college become an abuseing user? Do you intend to ban the whole college? Everyone on campus will likely connect from one of a handful of IPs
<FromGitter>
<elorest> Yeah. There's got to be some way to pull ip from the request. Hit up crystal core team about HTTP::Server.
<FromGitter>
<Prutheus> what do you mean by hit up?
<FromGitter>
<elorest> In terms of running nginx though. It's really easy same as using puma or php fpm5
<robacarp>
@elorest I looked through the docs on HTTP::Request the other day and there isn't anything in there about the client IP...my guess is it's not implemented yet
<FromGitter>
<elorest> Yeah same here. Seems like a strange oversight though.
<FromGitter>
<Prutheus> hm so what should i do now?
<FromGitter>
<elorest> Might be easy enough to add in amber. I'm hoping to have time soon to jump back in
<FromGitter>
<Prutheus> i need it in the next 2 days ...
<FromGitter>
<Prutheus> ;(
<FromGitter>
<elorest> Wouldn't nginx work like you were saying before?
<FromGitter>
<Prutheus> I dont want to setup nginx on my dev machine
<FromGitter>
<Prutheus> this is kinda strange and heavy
<robacarp>
that is to consume the X-Forwarded-For header which is created by nginx / aws elb
<robacarp>
if you don't have a proxy in front of your app, that header doesn't exist unless someone is being malicious
<FromGitter>
<ZeroPointEnergy> just saw that
<robacarp>
@prutheus my advice is, don't do anything with client ip addresses. Crystal doesn't have support for it in the http lib, but _even if it did_ it's a fake security without real teeth.
<FromGitter>
<Prutheus> so how else should i ban someone?
<robacarp>
email address?
<robacarp>
it's just as easy and just as unreliable as ip address
<FromGitter>
<eliasjpr> @Prutheus the IP detection in Amber relies in the server proxy configuration. If you are using a PAAS like Heroku for instance, they provide you with the correct IP address for the client. You have to read Heroku docs to understand it.
<robacarp>
make them tie their facebook account in, and ban that
<FromGitter>
<eliasjpr> Most service providers will give you the forwarded for header
<FromGitter>
<Prutheus> hm ok
<FromGitter>
<eliasjpr> The reason that might be returning `nil` has to do with the fact that the X-Forwarded-For header is not present
<FromGitter>
<Prutheus> yeah ok
<FromGitter>
<eliasjpr> You also have to add the Pipe::ClientIP Pipe to your pipeline
<FromGitter>
<eliasjpr> and initialize it with the expected headers
<FromGitter>
<eliasjpr> Again, your Amber app must be setup behin a proxy or proxies with the correct configuration that sets the X-Forwarded-For header
<FromGitter>
<eliasjpr> in order for the Amber client ip detection to work
<robacarp>
you can also use a browser extension to mimick this header
<robacarp>
not mimick, inject
<FromGitter>
<eliasjpr> I think doing it with `curl` wil also work no?
<FromGitter>
<Prutheus> do i need to add the pipe when i wanna use the X-Forwarded-For header?
<robacarp>
yeah, but if you're writing a website it's not convenient to do everything through curl
<FromGitter>
<Prutheus> Btw, how exactly do pipes work? i dont get it yet
<FromGitter>
<eliasjpr> @robacarp 👍
<FromGitter>
<eliasjpr> @Prutheus basically a request has to go through a series of transformation a pipe represents one of those transformation
<FromGitter>
<Prutheus> ok
<FromGitter>
<eliasjpr> request->(pipe)do_something->(pipe)do something 2-> (pipe) get Client IP -> response
<robacarp>
transformation is a much better way to describe it than "pipe"
<robacarp>
length doesn't matter to me, readability does. this is the same reason why Crystal switched from File.stat to File.info. It's more friendly to the developer.
<robacarp>
Transform and Transformation don't really capture what is happening, because a bunch of use cases of middleware don't transform anything
<FromGitter>
<eliasjpr> I think that `stat` was the wrong context base on the information that the method was returning
<robacarp>
it was returning the info that you get when you `stat` in a linux terminal
<FromGitter>
<eliasjpr> In regards to transform, handlers, middlewares you can name it as what suits best
<FromGitter>
<eliasjpr> It does not make a difference to me, since conceptually they all do the same thing
<robacarp>
thats a good point
<FromGitter>
<eliasjpr> pipe might be conceptually way to specific
<robacarp>
codifying the naming in any way isn't going to suffice because so many different possibilities exist
<FromGitter>
<eliasjpr> but thats was a long time ago
<FromGitter>
<eliasjpr> and it was based on the concept of `pipelines`
<robacarp>
yeah
<robacarp>
I don't actually have any better suggestions, I just know the naming there is confusing to people
<FromGitter>
<eliasjpr> the main reason why `pipe` was chosen. Another reason was to also reflec where this concept came from `Elixir/Phoenix`
<robacarp>
Rails middleware has the same problsem
<FromGitter>
<eliasjpr> Middlewares is even more confusing to me
<robacarp>
yeah Phoenix has pipelines and the naming is just as confusing that ecosystem
<FromGitter>
<eliasjpr> Agreed
<FromGitter>
<eliasjpr> Naming is one of the biggest problems in software development they say
<FromGitter>
<eliasjpr> software design I should say
<robacarp>
there are only two problems in software: cache invalidation, naming things, and off by one errors
<FromGitter>
<Prutheus> it works with nginx proxy, thanks. but client_ip returns the ip + port 0, why is there a port? (127.0.0.1:0)
<robacarp>
@prutheus what's your nginx config?
<FromGitter>
<Prutheus> same like of a link you gave me
<FromGitter>
<eliasjpr> @Prutheus thats because you are in dev mode and the x forwared for is adding the port to the string in production you wont see the port because http defaults to port 80 so that is assumed
<FromGitter>
<eliasjpr> @Prutheus do you have the port in the URL?
<FromGitter>
<Prutheus> no
<FromGitter>
<Prutheus> and it adds port 0
<FromGitter>
<Prutheus> but my server listens on 80
<FromGitter>
<Prutheus> so this is not the cause
<FromGitter>
<eliasjpr> it can be the implementation of ClientIP
<FromGitter>
<Prutheus> hm ok
<FromGitter>
<eliasjpr> Im checking
<robacarp>
this might be because of changes in crystal since 0.25
<robacarp>
a Socket::IpAddress contains a port reference
<FromGitter>
<eliasjpr> After looking at the NGINX config
<FromGitter>
<Prutheus> thanks for all, good night!
<FromGitter>
<eliasjpr> 0 is not a valid port
<FromGitter>
<eliasjpr> either assume port 80 if ssl is not enabled and 443 if enabled
<FromGitter>
<eliasjpr> and in dev/test we can pull the port from Amber settings
<robacarp>
what if client_ip just returned a string instead of a Socket::IPAddress?
<robacarp>
port doesn't really make sense in this context
<FromGitter>
<eliasjpr> I like the fact that is a valid Socket::IPAddress object
<FromGitter>
<eliasjpr> Port is part of the IP address based on the Socket::IPAddress class
<FromGitter>
<eliasjpr> Is up to you, I think it benefits that is a Socket::IPAddress instance and to have the port thats what I think
<FromGitter>
<robacarp> But port 80 is the server port, it has nothing to do with the client
<FromGitter>
<robacarp> So attaching 80 to it is incorrect
<FromGitter>
<eliasjpr> True
<FromGitter>
<eliasjpr> valid point
hightower3 has joined #amber
<hightower3>
Hey, right, the port in client_ip object is there just because there was no other type in Crystal
<hightower3>
which would contain only the IP
<FromGitter>
<eliasjpr> What are the consequences of using the Server port?
<robacarp>
it feels misleading
<hightower3>
Yeah, no value in using the server port. If anything, the original client's source port could be saved into that field
<robacarp>
which would be essentially random and > 10000 for every request
<hightower3>
Well, yes, which value it would hold would depend on the OS settings. And the real value/usefulness for the server would be questionable, but regardless of the number being "random" it would be correct.
wontruef_ has joined #amber
<FromGitter>
<eliasjpr> At the end I agree that returning the ip address only as string should be sufficient to satisfy the client ip pipe
wontruefree has quit [Ping timeout: 244 seconds]
<hightower3>
The reason why I didn't use the string in the first place is that using a string requires you to later convert string to some other representation if you want to invoke any IP-specific functions
<hightower3>
(Like functions that check whether IP is part of a range etc. (anything that relies on the numerical form of the IP))
<FromGitter>
<eliasjpr> I like having the Socket::IPAddress instance
<FromGitter>
<eliasjpr> is solid and a valid use case
<hightower3>
Yes, yes, I saw your comments. I meant the word "you" in general
<FromGitter>
<eliasjpr> would making the port negative be more clear?
<FromGitter>
<eliasjpr> new(address : "127.0.0.1", port : "-1")
<robacarp>
I think port 0 is pretty clear
<robacarp>
I do like the thought of ip address math and such
<hightower3>
It's confusing that Crystal's class named "IPAddress" contains a port too, as well as the fact that this field can't be nil
<FromGitter>
<eliasjpr> Port 0 is like a wildcard port that tells the system to find a suitable port number.
<FromGitter>
<eliasjpr> Port 0 is a reserved port so it might not be good to use
<FromGitter>
<eliasjpr> Actually this is fine
<FromGitter>
<eliasjpr> port 0 actually works pretty well, just have to know the purpose of the port 0 is
<FromGitter>
<eliasjpr> provide port 0 to bind() as its connection parameter. That triggers the operating system to automatically search for and return a suitable available port in the TCP/IP dynamic port number range. ⏎ ⏎ Note that the application will not actually be granted port 0 but rather some other dynamic port. The advantage of this programming convention is efficiency. Instead of each application having to implement and run
<FromGitter>
... code for trying multiple ports until they obtain a valid one, apps can rely on the operating system to do so.
<FromGitter>
<eliasjpr> Learn something new
<robacarp>
hightower3: I agree, but I can see why. I don't think Socket knows what an ipaddress without a port means
<robacarp>
Since this is a Socket::IPAddress, not just a general purpose IPAddress, I can see the reason port is mandatory