Saturday, 14 April 2012

Auto Login from Iphone Home Screen Shortcut using LocalStorage and Rack

If you ever worked on Mobile Application and if you have been ever asked to design a web auto login for iOS Home Screen Desktop every
time a user click the Home Screen Shortcut  then you might want settle down and read this post bcoz this can help you

The first that I came across when implementing the home screen shortcut how to manage the cookie and how to store in browser
(even when browser is closed)

Thank full to HTML5 as it provide a localStorage I quickly got the insight how where to store the cookie

For any one how aren’t aware of  HTML5 localStorage. HTML5 localStorage  provide API  for storing data locally on browser which can be
access any time  by your application in near future.

Now with clear insight of where to store the cookie the next task is how to access it and wrap it in request.

That when Rack Hit me

The idea is to mount a rack application on top rails middleware and then play around with Rails request/response cycle . Let me Hook
up the code to then explain you everything bit by bit
CODE = %{
  <script type="text/javascript">
    (function(){
      var RESEND_REQUEST = {{RESEND}};
      function isFullScreen() {
        return navigator.userAgent.match(/WebKit.*Mobile/) && !navigator.userAgent.match(/Safari/);
      }

      if(isFullScreen()) {
        if(!document.cookie.match(/{{REGEX}}/)){
          var storedValues = localStorage.getItem('__cookie__');
          if(storedValues){
            var values = storedValues.split(';');
            for(var i=0; i < values.length; i++)
              document.cookie = values[i];
          }
          document.cookie = '_cookieset_=1';

          if(RESEND_REQUEST){
            window.location.reload();
          }
        }
      }
    })()
  </script>
}

COOKIE = %{
  <script type="text/javascript">
    (function(){
      var COOKIE = "{{COOKIE}}";
      var lastCookie = null;
      setInterval(function(){
        if(lastCookie != ''+COOKIE){
          lastCookie = ''+COOKIE;
          localStorage.setItem('__cookie__', ''+COOKIE);
        }
      },1000);
    })()
  </script>
}  

  def initialize(app)
    @app = app
  end

  def call(env)
    if iphone_web_app?(env)
      if new_session?(env)
        [200,{'Content-Length' => code(true).length.to_s, 'Content-Type' => 'text/html'}, code(true)]
      else
        status, headers, body = @app.call(env)
        request = Rack::Request.new(env)
        response = Rack::Response.new([], status, headers)
        cookie = String.new
        request.cookies.each_pair do |key,value|
              cookie += "#{key}=#{value};"
        end
        body.each do |part|
          part.gsub!(/<\/head>/, "#{set_cookie(cookie)}")
          response.write(part)
        end
        response.finish
      end
    else
      @app.call(env)
    end
  end

  protected

  def code(resend=false)
    regex = "_session_id"
    if Rails.configuration.session_store.name == "ActionDispatch::Session::CookieStore"
      regex = Rails.configuration.session_options[:key]
    end
    CODE.gsub('{{RESEND}}', resend.to_s).gsub('{{REGEX}}',regex.to_s)
  end

  def set_cookie(cookie)
    COOKIE.gsub('{{COOKIE}}',cookie.to_s)
  end

  def new_session?(env)
    request = Rack::Request.new(env)
    if request.cookies['_cookieset_'].nil?
      true
    else
      false
    end
  end

  def iphone_web_app?(env)
    if env['HTTP_USER_AGENT']
      env['HTTP_USER_AGENT'] =~ /WebKit.*Mobile/ && !(env['HTTP_USER_AGENT'] =~ /Safari/)
    end
  end
Now the idea is to trap the request def new_session? which has no cookie associated with it return the code javascript in response body and extract the cookie from localStorage localStorage.getItem(‘__cookie__’);
associate it with document using document.cookie syntax and re-request the page using window.location.reload()

Voila there you have it next time you open your Home screen shortcut you would not be thrown to login screen citing no active session available.

Hooking  all of this in one gem called rack_iphone

Note : There are other way you can achieve the same using parameterized URL (where a URL will be identify with the parameter in it) something like GOOGLE does I Guess.

Providing few links which will further help you so that you don’t stumble upon any roadblocks when building the same
LocalStorage Issue

Hope that it help you in some way or other

Thanks

Viren Negi

No comments:

Post a Comment

What did I learn today?

Welcome to the what did I learn today series. The intention of this blog spot is to compose the stuff that I learnt day-to-day basics and jo...