rails responding to cross domain request developing locally, spotify app development - ruby-on-rails

So Im messing around with developing a spotify app, trying to get it to talk to my local rails application API. I cant get anything other than a req.status 0 when I try it.
I think its either a problem with the spotify manifest.json file, not allowing the port:3000 to go on the url you set in required permissions, but it also says the following in their documentation.
https://developer.spotify.com/technologies/apps/tutorial/
If you need to talk to an outside web API you're welcome to, as long as you abide by the rules set in the Integration Guidelines. Please note that when talking with a web API, the requests will come from the origin sp://$APPNAME (so sp://tutorial for our example) - make sure the service you are talking to accepts requests from such an origin.
So, Im not sure if rails is set to not allow this sort of thing, or if its an issue with the putting the port into the required permissions, but my request
var req = new XMLHttpRequest();
req.open("GET", "http://127.0.0.1:3000/api/spotify/track/1.json", true);
console.log(req);
req.onreadystatechange = function() {
console.log(req.status);
console.log(req.readyState);
if (req.readyState == 4) {
if (req.status == 200) {
console.log("Search complete!");
console.log(req.responseText);
}
}
};
req.send();
Always returns status 0 where as their example:
var req = new XMLHttpRequest();
req.open("GET", "http://ws.audioscrobbler.com/2.0/?method=geo.getevents&location=" + city + "&api_key=YOUR_KEY_HERE", true);
req.onreadystatechange = function() {
console.log(req.status);
if (req.readyState == 4) {
console.log(req);
if (req.status == 200) {
console.log("Search complete!");
console.log(req.responseText);
}
}
};
req.send();
Will return a 403 response at least. its like the request is not being made or something?
Anyone have any idea what might be going on?
Much appreciated!

When talking to external services from a Spotify App, even if they're running on your local machine, you need to make sure that two things are in place correctly:
The URL (or at least the host) is in the RequiredPermissions section of your manifest. Port doesn't matter. http://127.0.0.1 should be fine for your case.
The server is allowing the sp://your-app-id origin for requests, as noted in the documentation you pasted in your question. This is done by setting the Access-Control-Allow-Origin header in your service's HTTP response. People often set it to Access-Control-Allow-Origin: * to allow anything to make requests to their service.

Thanks for help, I got it figured out, I think it was multiple things, with one main Im an idiot moment for not trying that earlier
First off, I had to run rails on port 80, as obviously if Im accessing my site from 127.0.0.1:3000, thats not going to work if spotify app is requesting 127.0.0.1 unless I can load that directly in the browser, which you cannot unless you run on 80. That is done via
rvmsudo rails server -p 80
Need to use rvmsudo because changing port requires permissions.
Next I had to set access controll allow origin as noted above, that can be done in rails 3 by adding before filter to your app controller as follows.
class ApplicationController < ActionController::Base
logger.info "I SEE REQUEST"
before_filter :cor
def cor
headers["Access-Control-Allow-Origin"] = "*"
headers["Access-Control-Allow-Methods"] = %w{GET POST PUT DELETE}.join(",")
headers["Access-Control-Allow-Headers"] = %w{Origin Accept Content-Type X-Requested-With X-CSRF-Token}.join(",")
head(:ok) if request.request_method == "OPTIONS"
end
end
Finally, and most importantly (sigh), you cant just righclick and reload your spotify app when you make changes to your manifest file, exit spotify completely and restart it!

Related

Sails.js - get previouse url from request

How can i get previouse url without magic and in backend?
Now i get it through policies:
module.exports = function(req, res, next) {
if (!req.session.previouseUrls) {
req.session.previouseUrls = [];
}
req.session.previouseUrl = req.session.currentUrl || "/";
req.session.currentUrl = req.url;
req.session.previouseUrls.push(req.session.previouseUrl);
next();
};
but it's uncomfortable. Can i get previouse Url from backend simpler?
If you need to know the history (or just previous page) of the user's page requests purely on the client-side, could you query native HTML5 History?
..or if you need to support older browsers, maybe History.js?
I would be concerned with how you're doing it now for 2 reasons:
It's going to start filling up your session store. This may not be a big issue if you have short-lives sessions or not many users.
It could record not just traditional page views "clicks" but any request. Unless you're very carful about scoping this policy you may end up adding an Ajax call that goes through this policy check and you probably didn't intend for that.

Stoping saved request that triggered the login, always redirect to `/`

I have a web application that contains a REST api that is interacted with by the client application that lives at /. When a user session times out and the client js application makes a request to the REST api, that request will trigger a login event. Once the user logs in the user is then taken to the REST api endpoint which just displays a JSON response. I would like to hard wire the login page to always redirect to /.
Edit 1: I'm using spring-security-core plugin with the openid plugin as well and grails 2.0.4.
Edit 2: So I managed to get a solution working, however its a bit crude and I would like to know if there is a more elegant solution out there.
I created a simple filter in grails-app/conf/LoginRedirectFilters.groovy:
class RedirectLoginFilters {
def filters = {
redirectAfterLogin (uri: '/api/*') {
before = {
if (session["LOGGING_IN"])
redirect uri: "/"
}
after = {
if (session["LOGGING_IN"])
session["LOGGING_IN"] = false
}
}
}
}
And in my auth function inside of OpenIdController.groovy I added the session flag LOGGING_IN:
def auth = {
def config = SpringSecurityUtils.securityConfig
if (springSecurityService.isLoggedIn()) {
redirect uri: config.successHandler.defaultTargetUrl
return
}
session["LOGGING_IN"] = true
.
.
.
This is working properly by only checking if the LOGGING_IN flag is true when an api endpoint is called, and it also kills the flag after one request so it won't interfere with subsequent client api calls. I realize this is pretty convoluted, so if there is a better solution please let me know, thanks!
Why can't you use the same "springSecurityService.isLoggedIn()" inside your filter as well? I'm pretty sure that works as well.
I think I'm misunderstanding exactly what you want to achieve, but if you always want to redirect to '/' after a successful login, just set these properties in your Config.groovy:
grails.plugins.springsecurity.successHandler.alwaysUseDefault = true
grails.plugins.springsecurity.successHandler.defaultTargetUrl = "/"
If you want different behaviour to this, you'll have to flesh out your question.

CI 2.0.3 session heisenbug: session is lost after some time 20 minutes, only on server redirect, nothing suspicious in the logs

I can't seem to make any progress with this one. My CI session settings are these:
$config['sess_cookie_name'] = 'ci_session';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'ci_sessions';
$config['sess_match_ip'] = FALSE;
$config['sess_match_useragent'] = FALSE;
$config['sess_time_to_update'] = 7200;
$config['cookie_prefix'] = "";
$config['cookie_domain'] = "";
$config['cookie_path'] = "/";
$config['cookie_secure'] = FALSE;
The session library is loaded on autoload. I've commented the sess_update function to prevent an AJAX bug that I've found about reading the CI forum.
The ci_sessions table in the database has collation utf8_general_ci (there was a bug that lost the session after every redirect() call and it was linked to the fact that the collation was latin1_swedish_ci by default).
It always breaks after a user of my admin section tries to add a long article and clicks the save button. The save action looks like this:
function save($id = 0){
if($this->my_model->save_article($id)){
$this->session->set_flashdata('message', 'success!');
redirect('admin/article_listing');
}else{
$this->session->set_flashdata('message', 'errors encountered');
redirect('admin/article_add');
}
}
If you spend more than 20minutes and click save, the article will be added but on redirect the user will be logged out.
I've also enabled logging and sometimes when the error occurs i get the message The session cookie data did not match what was expected. This could be a possible hacking attempt. but only half of the time. The other half I get nothing: a message that I've placed at the end of the Session constructor is displayed and nothing else. In all the cases if I look at the cookie stored in my browser, after the error the cookie's first part doesn't match the hash.
Also, although I know Codeigniter doesn't use native sessions, I've set session.gc_maxlifetime to 86400.
Another thing to mention is that I'm unable to reproduce the error on my computer but on all the other computers I've tested this bug appears by the same pattern as mentioned above.
If you have any ideas on what to do next, I'd greatly appreciate them. Changing to a new version or using a native session class (the old one was for CI 1.7, will it still work?) are also options I'm willing to consider.
Edit : I've run a diff between the Session class in CI 2.0.3 and the latest CI Session class and they're the same.
Here's how I solved it: the standards say that a browser shouldn't allow redirects after a POST request. CI's redirect() method is sending a 302 redirect by default. The logical way would be to send a 307 redirect, which solved my problem but has the caveat of showing a confirm dialog about the redirect. Other options are a 301 (meaning moved permanently) redirect or, the solution I've chosen, a javascript redirect.

OS X Wiki/Blog Server API

I'm working on a client app for iOS to edit the built-in Wiki/Blog on Mac OS X Server (Snow Leopard & Lion).
It seems that we are able to use MetaWeblog , Atom API(I've tried but failed) or XML-RPC.
However, I can't find any API document for it.
So my question is, where can I find the documents, or some open source samples?
All samples I found can't deal with the OS X Server.
Much appreciate!
Peak
Update:
Heres the standard structure of the Wiki system:
I can't even get the list of the 'group_name' under ~/Groups/
The javascript source code for the wiki is not obfuscated, and it seems simple enough to serve as documentation. For example, the authentication process:
sendAuthenticationPlain: function() {
$('webauth').addClassName('verifying').removeClassName('error');
var username = $F('username');
var password = $F('password');
var csrf = $F('authenticity_token');
var plainResponse = "username="+username+"&password="+password
this.setRememberMeCookie();
var ajaxReq = new Ajax.Request(window.location.protocol + '//' + window.location.host + "/auth/plain_login", {
method: 'post',
requestHeaders: {'X-CSRF-Token': csrf},
onComplete: this.gotAuthentication.bind(this),
postBody: plainResponse
});
return false;
},
gotAuthentication: function(origRequest) {
if (origRequest.responseJSON) {
var jsonObject = origRequest.responseJSON
if (jsonObject['success']) {
var redirect = jsonObject['redirect'];
var authToken = jsonObject['auth_token'];
this.successCallback(authToken, redirect);
} else {
var errorString = jsonObject['error_string']
this.failureCallback(errorString);
}
}
},
So you send a POST request to auth/plain_login, containing just the username/password in the POST data and an X-CSRF-Token header who's value comes from the <input type="hidden" name="authenticity_token" /> element on the page. The server returns a JSON string containing 'success' boolean.
You can also use safari/chrome's developer tools to monitor ajax requests to/from the server, for example this is the JSON contents of a PUT request to save a wiki page:
I'm working on the latest Lion server, for an access via an app. The structure of the Lion server web service is based on ruby on rails, and is easy to understand ( I have no ruby experience before). However, the whole system(for the implemented part) is not designed for API access. For example, the auth system is based on Cookie authentication(session id or something). not all the output of the request has a json response. Not any failed request responses with a json body.
all the work need to be done by ur self.
The first is to authenticate with the server. all the process is exposed to you:
'wiki/api/csrf' to get the X-CSRF-Token value
'auth/challenge_advanced?username=xxxx' to get a challenge parameters
'auth/digest_login' to use md5-sess digest to login
while, the md5-sess digest is calculated by your own code following to the digest.js (objective-c for me, with CC_md5 lib)
then you can added json render support to ur required controllers, such as,
respond_to do |format|
format.html
format.js { render_js_pagination_response(#search, 'people/entitylist_item') }
format.json { #new added json support
rs = []
#search.results.each do |r|
nr = filterUserInfo r # I only need some of the all properties
rs.push nr
end
render :json => rs
}
end
One important thing is, the lion server use web auth/cookie to authorize an access, so your request lib/api must handle the cookies.
all above is a simplest solution the the api/json access, but not the best one. U had better to re-work all access progress to suit the api access.
BTW: u can copy the whole /usr/share/collabd/ into ur own project's dir, then modify all /your projects path/collab/coreclient/config/collabcore{1,2,3,4}.yml, change the production to development.
so u can start a development server app under collab/coreclient with:
sudo -u _teamsserver thin start
access to the server thru http://localhost:3000

Twitter oAuth callbackUrl - localhost development

Is anyone else having a difficult time getting Twitters oAuth's callback URL to hit their localhost development environment.
Apparently it has been disabled recently. http://code.google.com/p/twitter-api/issues/detail?id=534#c1
Does anyone have a workaround. I don't really want to stop my development
Alternative 1.
Set up your .hosts (Windows) or etc/hosts file to point a live domain to your localhost IP. such as:
127.0.0.1 xyz.example
where xyz.example is your real domain.
Alternative 2.
Also, the article gives the tip to alternatively use a URL shortener service. Shorten your local URL and provide the result as callback.
Alternative 3.
Furthermore, it seems that it works to provide for example http://127.0.0.1:8080 as callback to Twitter, instead of http://localhost:8080.
I just had to do this last week. Apparently localhost doesn't work but 127.0.0.1 does Go figure.
This of course assumes that you are registering two apps with Twitter, one for your live www.mysite.example and another for 127.0.0.1.
Just put http://127.0.0.1:xxxx/ as the callback URL, where xxxx is the port for your framework
Yes, it was disabled because of the recent security issue that was found in OAuth. The only solution for now is to create two OAuth applications - one for production and one for development. In the development application you set your localhost callback URL instead of the live one.
Callback URL edited
http://localhost:8585/logintwitter.aspx
Convert to
http://127.0.0.1:8585/logintwitter.aspx
This is how i did it:
Registered Callback URL:
http://127.0.0.1/Callback.aspx
OAuthTokenResponse authorizationTokens =
OAuthUtility.GetRequestToken(ConfigSettings.getConsumerKey(),
ConfigSettings.getConsumerSecret(),
"http://127.0.0.1:1066/Twitter/Callback.aspx");
ConfigSettings:
public static class ConfigSettings
{
public static String getConsumerKey()
{
return System.Configuration.ConfigurationManager.AppSettings["ConsumerKey"].ToString();
}
public static String getConsumerSecret()
{
return System.Configuration.ConfigurationManager.AppSettings["ConsumerSecret"].ToString();
}
}
Web.config:
<appSettings>
<add key="ConsumerKey" value="xxxxxxxxxxxxxxxxxxxx"/>
<add key="ConsumerSecret" value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
</appSettings>
Make sure you set the property 'use dynamic ports' of you project to 'false' and enter a static port number instead. (I used 1066).
I hope this helps!
Use http://smackaho.st
What it does is a simple DNS association to 127.0.0.1 which allows you to bypass the filters on localhost or 127.0.0.1 :
smackaho.st. 28800 IN A 127.0.0.1
So if you click on the link, it will display you what you have on your local webserver (and if you don't have one, you'll get a 404). You can of course set it to any page/port you want :
http://smackaho.st:54878/twitter/callback
I was working with Twitter callback url on my localhost. If you are not sure how to create a virtual host ( this is important ) use Ampps. He is really cool and easy. In a few steps you have your own virtual host and then every url will work on it. For example:
download and install ampps
Add new domain. ( here you can set for example twitter.local) that means your virtual host will be http://twitter.local and it will work after step 3.
I am working on Win so go under to your host file -> C:\Windows\System32\Drivers\etc\hosts and add line: 127.0.0.1 twitter.local
Restart your Ampps and you can use your callback. You can specify any url, even if you are using some framework MVC or you have htaccess url rewrite.
Hope This Help!
Cheers.
Seems nowadays http://127.0.0.1 also stopped working.
A simple solution is to use http://localtest.me instead of http://localhost it is always pointing to 127.0.0.1 And you can even add any arbitrary subdomain to it, and it will still point to 127.0.0.1
See Website
When I develop locally, I always set up a locally hosted dev name that reflects the project I'm working on. I set this up in xampp through xampp\apache\conf\extra\httpd-vhosts.conf and then also in \Windows\System32\drivers\etc\hosts.
So if I am setting up a local dev site for example.com, I would set it up as example.dev in those two files.
Short Answer: Once this is set up properly, you can simply treat this url (http://example.dev) as if it were live (rather than local) as you set up your Twitter Application.
A similar answer was given here: https://dev.twitter.com/discussions/5749
Direct Quote (emphasis added):
You can provide any valid URL with a domain name we recognize on the
application details page. OAuth 1.0a requires you to send a
oauth_callback value on the request token step of the flow and we'll
accept a dynamic locahost-based callback on that step.
This worked like a charm for me. Hope this helps.
It can be done very conveniently with Fiddler:
Open menu Tools > HOSTS...
Insert a line like 127.0.0.1 your-production-domain.com, make sure that "Enable remapping of requests..." is checked. Don't forget to press Save.
If access to your real production server is needed, simply exit Fiddler or disable remapping.
Starting Fiddler again will turn on remapping (if it is checked).
A pleasant bonus is that you can specify a custom port, like this:
127.0.0.1:3000 your-production-domain.com (it would be impossible to achieve this via the hosts file). Also, instead of IP you can use any domain name (e.g., localhost).
This way, it is possible (but not necessary) to register your Twitter app only once (provided that you don't mind using the same keys for local development and production).
edit this function on TwitterAPIExchange.php at line #180
public function performRequest($return = true)
{
if (!is_bool($return))
{
throw new Exception('performRequest parameter must be true or false');
}
$header = array($this->buildAuthorizationHeader($this->oauth), 'Expect:');
$getfield = $this->getGetfield();
$postfields = $this->getPostfields();
$options = array(
CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => $this->url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false
);
if (!is_null($postfields))
{
$options[CURLOPT_POSTFIELDS] = $postfields;
}
else
{
if ($getfield !== '')
{
$options[CURLOPT_URL] .= $getfield;
}
}
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
if ($return) { return $json; }
}
I had the same challenge and I was not able to give localhost as a valid callback URL. So I created a simple domain to help us developers out:
https://tolocalhost.com
It will redirect any path to your localhost domain and port you need. Hope it can be of use to other developers.
set callbackurl in twitter app : 127.0.0.1:3000
and set WEBrick to bind on 127.0.0.1 instead of 0.0.0.0
command : rails s -b 127.0.0.1
Looks like Twitter now allows localhost alongside whatever you have in the Callback URL settings, so long as there is a value there.
I struggled with this and followed a dozen solutions, in the end all I had to do to work with any ssl apis on local host was:
Go download: cacert.pem file
In php.ini * un-comment and change:
curl.cainfo = "c:/wamp/bin/php/php5.5.12/cacert.pem"
You can find where your php.ini file is on your machine by running php --ini in your CLI
I placed my cacert.pem in the same directory as php.ini for ease.
These are the steps that worked for me to get Facebook working with a local application on my laptop:
goto apps.twitter.com
enter the name, app description and your site URL
Note: for localhost:8000, use 127.0.0.1:8000 since the former will not work
enter the callback URL matching your callback URL defined in TWITTER_REDIRECT_URI your application
Note: eg: http://127.0.0.1/login/twitter/callback (localhost will not work).
Important enter both the "privacy policy" and "terms of use" URLs if you wish to request the user's email address
check the agree to terms checkbox
click [Create Your Twitter Application]
switch to the [Keys and Access Tokens] tab at the top
copy the "Consumer Key (API Key)" and "Consumer Secret (API Secret)" to TWITTER_KEY and TWITTER_SECRET in your application
click the "Permissions" tab and set appropriately to "read only", "read and write" or "read, write and direct message" (use the least intrusive option needed for your application, for just and OAuth login "read only" is sufficient
Under "Additional Permissions" check the "request email addresses from users" checkbox if you wish for the user's email address to be returned to the OAuth login data (in most cases check yes)

Resources