Best way to serve files? - ruby-on-rails

I'm a novice web developer with some background in programming (mostly Python).
I'm looking for some basic advice on choosing the right technology.
I need to serve files over the internet (mp3's), but I need to implement some
control on the access:
1. Files will be accessible only for authorized users.
2. I need to keep track on how many times a file was loaded, by whom, etc.
What might be the best technology to implement this? That is, should I
learn Apache, or maybe Django? or maybe something else?
I'm looking for a 'pointer' in the right direction.
Thank!
R

If you need to track/control the downloads that suggests that the MP3 urls need to be routed through a Rails controller. Very doable. At that point you can run your checks, track your stats, and send the file back.
If it's a lot of MP3's, you would like to not have Rails do the actual sending of the MP3 data as it's a waste of it's time and ties up an instance. Look into xsendfile where Rails can send a response header indicating the file path to send and apache will intercept it and do the actual sending.
https://tn123.org/mod_xsendfile/
http://rack.rubyforge.org/doc/classes/Rack/Sendfile.html

You could use Django and Lighttpd as a web server. With Lighttpd you can use mod_secdownload, wich enables you to generate one time only urls.
More info can be found here: http://redmine.lighttpd.net/projects/1/wiki/Docs_ModSecDownload
You can check for permissions in your Django (or any other) app and then redirect the user to this disposable URL if he passed the permission check.

Related

Rails connect to Asterisk and make phone calls

Hi i have googled all day long but i can't find an answer.
I have to write a web app which talks to asterisk.
It should be able to do ClicktoCall operations.
Can you guys recommend something ?
I came across a few projects but I'm still not sure.
I just want to connect to Asterisk and do calls from the web app.
thanks
If you're a Ruby programmer the best way for you to hook into Asterisk is adhearsion. It wraps up Asterisk's AGI and Manager (MAPI) APIs for you.
Also hAve a look at SIP, asterisk, adhearson and VoIP and in particular Adam Kalsey's answer. He works for Tropo which sponsor the adhearsion project.
First you need to know, that the protocol Asterisk uses is SIP, you can learn more at the Wikipedia.
Since you want to use an rails application, you may want to use ruby as well, so there's a ruby implementation named OverSip, you can check their API and see if it fits your requirements.
If you are aiming at web calls, you'll need an WebRTC, Flash or Java applet. For WebRTC you can check sipML5 for an opensource solution.
You can also opt for an interface, that will start a call from one number to another, using your phone. When the first call is picked up the server starts ringing in the destination.
Also you could make use of cloud communications providers like twilio, tropo, etc.
Try this Google search:
rails asterisk manager interface
I saw some interesting things right off. I am not trying to be one if those Use Google type people, just didn't want to paste all the links in that I found from this Google search.
Check it out, hope it helps.
There are several ways to do this but the three easiest ones are
1. Generate a call file on the Asterisk server
These files should be written to the dir
/var/spool/asterisk/outgoing
Asterisk will then pickup the file, process and delete it.
It's pretty aggressive when doing this so it's recommended to write the file into a temporary directory and then move it to the spool dir for processing.
An tutorial of the file format is here:
https://www.voip-info.org/asterisk-auto-dial-out/
(I personally feel this is a bit "hacky", and prefer doing it with an API call)
2. Generate the call by the AMI API interface.
Use the Originate function of the AMI API to generate the call. It's pretty easy to set this up just configure the manager.conf file whitch sets up a HTTP server on port 5038 from witch you can call the API.
https://www.voip-info.org/asterisk-config-managerconf/
3. Set up the call using the ARI API
First you need to setup ari.conf, this is enough for now:
[general]
enabled = yes
pretty=yes
allowed_origins=http://ari.asterisk.org
[my_username]
type = user
read_only = no
password = my_password
password_format = plain
This is a little bit more complicated to set up, but it really isn't that hard if you just get past the technical geek-speak. Just set up two channels, setup a mixing bridge and add both channels to the bridge.
To set up a click2call you dont even need to do that...
This is the call we use (ruby):
where
#{sip_id} is your registered SIP username
#{number} is the extension that is sent to the dialplan
#{USERNAME}
#{PASSWORD} is from ari.conf
HTTParty.post("http://sipserver.com/ari/channels?endpoint=SIP/#{sip_id}&extension=#{number}&context=outgoing&priority=1&timeout=30&api_key=#{USERNAME}:#{PASSWORD}")
(Note that you need to send the variabels for the variable parameter as a separate JSON for the originate command if you need to send them)
A really useful tool to understand how this works is the swagger at
http://ari.asterisk.org. We already allowed this origin in ari.conf so it should be ready to go. Remember to open your ports in firewalls etc.
Setup your Server IP and port and the API_KEY is in this format: my_username:my_password

Embedding Flash Media Services (Red5) and Authorization

An architectural question.
My site needs to allow the user to record video and upload it to the "site". I've been poking around a fair bit and it seems I have to use some kind of media server to achieve this aim. As I'm introducing this secondary server into the system (I seek to embed the flash app residing on this server into the HTML delivered by the site) it occurs to me that this broadens the scope of security a lot. What scares me is attackers trying to embed the flash app themselves or attempting to impersonate clients (or anything else I haven't thought of yet!).
I was therefore wondering how people secure their applications with such an architecture. Sure I can do what is suggested here, a decent band-aid for now but afaik the domain information can technically be falsified by the client.
I could separate out the auth of the site giving me a WebServer, an AuthServer and a MediaServer enabling the MediaServer to separately auth. Getting the user to log into both sites is obviously onerous and passing around the user's login creds and securing all connections sounds ugly and averse to best practice.
As far as I can see my best bet is some kind of temporary token that the auth server creates. So the website kicks the auth server after logging in to generate the token which the site can then pass to the media server (as part of the flash vars) and the MediaServer itself can use to double check against the auth server.
I'm relatively new to Red5, Flash and web security so I was wondering if the following sounds sane, secure and/or necessary. Also if anyone knows of decent tools to use for such an auth system and whether there is something already kicking about in ASP.NET auth for such a purpose.
the solution provided in your link ... you should read my second comment.
The first about virtual hosts is wrong! My comment does actually tell you (at least one) solution to secure your app.
You could for example pass a SESSION_ID in the connect method to Red5. The user would get the SESSION_ID from another webservice call before he invokes the record or playback method.
The SESSION_ID might be even some kind of temporary token, that is only valid for 15 minutes and only usable a single time for exactly that video. How far you implement that is a matter of how secure your mechanism needs to be.
Sebastian

Rails implementation for securing S3 documents

I would like to protect my s3 documents behind by rails app such that if I go to:
www.myapp.com/attachment/5 that should authenticate the user prior to displaying/downloading the document.
I have read similar questions on stackoverflow but I'm not sure I've seen any good conclusions.
From what I have read there are several things you can do to "protect" your S3 documents.
1) Obfuscate the URL. I have done this. I think this is a good thing to do so no one can guess the URL. For example it would be easy to "walk" the URL's if your S3 URLs are obvious: https://s3.amazonaws.com/myapp.com/attachments/1/document.doc. Having a URL such as:
https://s3.amazonaws.com/myapp.com/7ca/6ab/c9d/db2/727/f14/document.doc seems much better.
This is great to do but doesn't resolve the issue of passing around URLs via email or websites.
2) Use an expiring URL as shown here: Rails 3, paperclip + S3 - Howto Store for an Instance and Protect Access
For me, however this is not a great solution because the URL is exposed (even for just a short period of time) and another user could perhaps in time reuse the URL quickly. You have to adjust the time to allow for the download without providing too much time for copying. It just seems like the wrong solution.
3) Proxy the document download via the app. At first I tried to just use send_file: http://www.therailsway.com/2009/2/22/file-downloads-done-right but the problem is that these files can only be static/local files on your server and not served via another site (S3/AWS). I can however use send_data and load the document into my app and immediately serve the document to the user. The problem with this solution is obvious - twice the bandwidth and twice the time (to load the document to my app and then back to the user).
I'm looking for a solution that provides the full security of #3 but does not require the additional bandwidth and time for loading. It looks like Basecamp is "protecting" documents behind their app (via authentication) and I assume other sites are doing something similar but I don't think they are using my #3 solution.
Suggestions would be greatly appreciated.
UPDATE:
I went with a 4th solution:
4) Use amazon bucket policies to control access to the files based on referrer:
http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?UsingBucketPolicies.html
UPDATE AGAIN:
Well #4 can easily be worked around via a browsers developer's tool. So I'm still in search of a solid solution.
You'd want to do two things:
Make the bucket and all objects inside it private. The naming convention doesn't actually matter, the simpler the better.
Generate signed URLs, and redirect to them from your application. This way, your app can check if the user is authenticated and authorized, and then generate a new signed URL and redirect them to it using a 301 HTTP Status code. This means that the file will never go through your servers, so there's no load or bandwidth on you. Here's the docs to presign a GET_OBJECT request:
https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Presigner.html
I would vote for number 3 it is the only truly secure approach. Because once you pass the user to the S3 URL that is valid till its expiration time. A crafty user could use that hole the only question is, will that affect your application?
Perhaps you could set the expire time to be lower which would minimise the risk?
Take a look at an excerpt from this post:
Accessing private objects from a browser
All private objects are accessible via
an authenticated GET request to the S3
servers. You can generate an
authenticated url for an object like
this:
S3Object.url_for('beluga_baby.jpg', 'marcel_molina')
By default
authenticated urls expire 5 minutes
after they were generated.
Expiration options can be specified
either with an absolute time since the
epoch with the :expires options, or
with a number of seconds relative to
now with the :expires_in options:
I have been in the process of trying to do something similar for quite sometime now. If you dont want to use the bandwidth twice, then the only way that this is possible is to allow S3 to do it. Now I am totally with you about the exposed URL. Were you able to come up with any alternative?
I found something that might be useful in this regard - http://docs.aws.amazon.com/AmazonS3/latest/dev/AuthUsingTempFederationTokenRuby.html
Once a user logs in, an aws session with his IP as a part of the aws policy should be created and then this can be used to generate the signed urls. So in case, somebody else grabs the URL the signature will not match since the source of the request will be a different IP. Let me know if this makes sense and is secure enough.

Serving files through controllers with partial download support

I need to serve files through grails, only users with permission have access, so I cant serve them with a static link to a container. The system is able to stream binary files to the client without problems,but now (for bandwidth performance issues on the client) I need to implement segmented or partial downloads in the controllers.
Theres a plugin or proven solution to this problem?
May be some kind of tomcat/apache plugin to restrict access to files with certain rules or temporal tickets so I can delegate the "resume download" or "segmented download" problem to the container.
Also i need to log and save stats on the downloads of the users.
I need good performance so, I think doing this in the controller is not good idea.
Sorry bad english.
There is a plugin for apache - https://tn123.org/mod_xsendfile/ It doesn't matter what you're using behind apache at this case. By using this plugin you will respond with special header X-SENDFILE, with path to file to serve, and Apache will take care about actual file downloading for current request.
If you're using Nginx, you have to use X-Accel-Redirect header, see http://wiki.nginx.org/XSendfile

Intercept request for file download and send to Rails app?

I would like to make a Rails app to create a pretty download page for any file requested either through a link or by typing the url of the file. Is there a way to intercept the request for a file in Apache or elsewhere and send it to the app so it can generate the page?
I'd also prefer not to change the url when redirecting to the app, but it doesn't really matter either way.
So to wrap up, turn this: http://files.spherecat1.com/stuff.txt, into this:
http://files.spherecat1.com/download-page-mockup.png
(Image for illustrative purposes only and may not accurately depict final product. It's fun to add disclaimers to everything.)
Do you mean an entire Rails app just for that? Seems like overkill - you can use Sinatra, a single route, and their send_file function with much greater ease. It also deploys on Apache with Passenger.
If you have control over this thing, and you only plan to offer downloads in this way and not in any other, you should probably store the files in some non-public directory and instead allow your Rails/Sinatra app to access and push the files to the user. (Again, with send_file, that's easy.) Why put a file in your web root if your users will never access it that way?

Resources