faustinoaq changed the topic of #amber to: Welcome to Amber Framework community! | https://amberframework.org | Developer happiness, productivity and bare metal performance | GH: https://github.com/amberframework | Docs: https://docs.amberframework.org | Gitter: https://gitter.im/amberframework/amber | IRC Logger: https://irclog.whitequark.org/amber | Amber::Server.start
marenz has joined #amber
<FromGitter> <ugran> Hi guys
<FromGitter> <ugran> Is there something like rails devise gem
<FromGitter> <ugran> for amber?
<FromGitter> <conradwt> @faustinoaq Just wanted to let you know that both the `shards` and `amber` PRs (i.e. https://github.com/macports/macports-ports/pull/2147 and https://github.com/macports/macports-ports/pull/2163) have been approved by the MacPorts team. Now, I simply need to update the docs. just thought I would let you know.
<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 in your nginx configuration, you specify the header(s) you want to set when it proxies requests with proxy_set_header. The most common header is X-Forwarded-For, as seen here: https://serverfault.com/questions/618456/getting-the-client-ip-when-passing-through-a-reverse-proxy#618683
<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
<FromGitter> <ZeroPointEnergy> @Prutheus Did not follow the whole conversation, so I'm sorry if you already tried that, The controller delegates an method client_ip to the http context, so that should be accessible in the controller: https://github.com/amberframework/amber/blob/master/src/amber/controller/base.cr#L21
<FromGitter> <ZeroPointEnergy> But I did not try it, so don't blame me if it does not work :-)
<FromGitter> <Prutheus> how to call it?
<FromGitter> <ZeroPointEnergy> client_ip
<FromGitter> <ZeroPointEnergy> in a controller method
<FromGitter> <Prutheus> ok let me try
<FromGitter> <Prutheus> tis nil
<FromGitter> <Prutheus> *its
<FromGitter> <ZeroPointEnergy> yeah, I just checked it's nil here as well
<FromGitter> <ZeroPointEnergy> but the method is there
<FromGitter> <Prutheus> hm
<FromGitter> <Prutheus> any idea?
<FromGitter> <ZeroPointEnergy> yeah looks like this is not really implemented on crystals side from this: https://github.com/amberframework/amber/blob/master/src/amber/controller/base.cr#L21
<FromGitter> <Prutheus> what should i do now?
<FromGitter> <ZeroPointEnergy> It seams amber has implemeted their own detection, https://github.com/amberframework/amber/pull/564
<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> <Prutheus> how?
<FromGitter> <eliasjpr> ```pipeline :web do ⏎ Pipe::ClientIp.new({"Custom-Header-Here"}] ⏎ end``` [https://gitter.im/amberframework/amber?at=5b466f6c866e0c6b159e106d]
<FromGitter> <eliasjpr> Here are some notes about the X-Forwared-For header https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
<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"
<FromGitter> <eliasjpr> in source code it will be a lot of typing
<FromGitter> <eliasjpr> `Transform::ClientIP` or `Transformation::ClientIP`
<FromGitter> <eliasjpr> we could have just kept it as Handlers
<FromGitter> <eliasjpr> @Prutheus this is a good resource for you to read about pipelines https://docs.amberframework.org/amber/guides/routing/pipelines
<FromGitter> <eliasjpr> and 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> <eliasjpr> you have the REAL-IP header
<FromGitter> <eliasjpr> so I think you can just use that
<robacarp> .to_s on a Socket::IPAddress is going to include the port
<robacarp> since this Socket::IPAddress is initialized without a port, it's showing as 0
<FromGitter> <eliasjpr> I wonder if thats by design
<FromGitter> <Prutheus> thanks
<FromGitter> <eliasjpr> I belive we have to change this line https://github.com/amberframework/amber/blob/master/src/amber/pipes/client_ip.cr#L23
<FromGitter> <eliasjpr> to use a valid port
<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
<robacarp> @eliasjpr nice. good to know
<hightower3> Oh, good point
marenz has quit [Ping timeout: 260 seconds]
hightower3 has quit [Ping timeout: 260 seconds]
hightower3 has joined #amber
hightower3 has quit [Ping timeout: 244 seconds]
wontruef_ has quit [Quit: bye]
wontruefree has joined #amber
hightower3 has joined #amber
wontruefree has quit [Quit: bye]