I have a Sinatra application, in which one of the rules expect the URL to contain the session id (returned from a previously called URL). How to overload the session with the one referenced by the session ID?
use Rack::Session::Pool
get "example/:session_id" do
sessionId = params[:session_id]
# how to reload the session now, using the sessionId?
end
Thanks for the help!
Session ID in Path
If you must use a session id from the path, you can use this hacky way
# app.rb
require 'sinatra'
configure do
use Rack::Session::Pool, :key => 'session_id'
end
get "/example/:session_id" do
session.id = params[:session_id]
session[:force_load] = 'force' # force session.load!()
session.delete(:force_load) # remove dummy value
session[:count] = session[:count].to_i + 1
session.inspect
end
Session ID in Request Params
A supported way would be to set :cookie_only option to false if you are willing to move session_id to a request parameter (query parameter or body parameter)
# app.rb
require 'sinatra'
configure do
use Rack::Session::Pool, {
:key => 'session_id',
:cookie_only => false, # adds request params as source for session id
}
end
# works with /example?session_id=
get '/example' do
session[:count] = session[:count].to_i + 1
session.inspect
end
Demo
$ ruby app.rb &> /dev/null &
$ curl -i localhost:4567/example?session_id=
HTTP/1.1 200 OK
Set-Cookie: session_id=2a06759c64c130bc45036076; path=/; HttpOnly
{"count"=>1}
$ curl -i localhost:4567/example?session_id=2a06759c64c130bc45036076
HTTP/1.1 200 OK
Set-Cookie: session_id=2a06759c64c130bc45036076; path=/; HttpOnly
{"count"=>2}
$ kill %1
Related
I have started building a web scraper to get some data for an API, however the url requires a 'continue as guest' for each daily visit. This is the cookie I from the request header:
web_site=eyJpdiI6Im0ySWpxMFdLVW56RVk0NzU5cEZNZlE9PSIsInZhbHVlIjoiWU5XVWNzZTlMejEzOHFhQ0hsSkVlbmZxbm5zeWNuU0tGZ1hNOUNuUGZQdFFJUDB2M2M4NFRzbGx2WjdMZ1NTQ0dUZ0ZqRmNUVmk5XC9JeThVTlhVZm1RPT0iLCJtYWMiOiI4ZTBhZjUxZWFmNDhiZjI0MzE1OGMyNjY2N2EyOTkyODM4N2NlYWIzZTBmNmI2ZmExMDg5ZTcyYTY3MzM2MWZiIn0%3D;
expires=Tue, 01-Mar-2022 20:00:34 GMT; Max-Age=7200;
path=/;samesite=none;Secure; domain=.website.co.uk
So i am trying to add this cookie to my request but can't seem to get the formatting right (or am doing something else wrong).
This
browser.cookies.add('openplay_session', 'eyJpdiI6Ill6RFRPeXJzcktzcndCM3pEM1I0S3c9PSIsInZhbHVlIjoiN1pCRDZjaXRBbUpSaU1BOFhEVkVld0tsWXlcL0l6RlNISmdoQ25JWnpcL3BxNVREWWFaWk9kY1wvTDVFMUI0aW81TmptN0ppTFlISkxMclhianB1WlFRWnc9PSIsIm1hYyI6IjE1NTVjZjJjZTQzYzQ0ODdmZTdlODY2ZDBjODdjNzYyY2Q5ZGJmMDYxNjIyOGUzZjU3N2JjZWYwMjRjZjVjNzUifQ%3D%3D', path='/', Secure = true, domain='.openplay.co.uk')
returns:
`add': wrong number of arguments (given 5, expected 2..3)
(ArgumentError)
Full code so far (not complete as I cant access the tables content w/o the cookie):
require 'watir'
require 'webdrivers'
require 'nokogiri'
require 'securerandom'
browser = Watir::Browser.new
browser.goto 'https://www.website.co.uk/booking'
browser.cookies.add('open_session', 'eyJpdiI6Ill6RFRPeXJzcktzcndCM3pEM1I0S3c9PSIsInZhbHVlIjoiN1pCRDZjaXRBbUpSaU1BOFhEVkVld0tsWXlcL0l6RlNISmdoQ25JWnpcL3BxNVREWWFaWk9kY1wvTDVFMUI0aW81TmptN0ppTFlISkxMclhianB1WlFRWnc9PSIsIm1hYyI6IjE1NTVjZjJjZTQzYzQ0ODdmZTdlODY2ZDBjODdjNzYyY2Q5ZGJmMDYxNjIyOGUzZjU3N2JjZWYwMjRjZjVjNzUifQ%3D%3D', path='/', domain='.website.co.uk')
parsed_page = Nokogiri::HTML(browser.html)
File.open("parsed.txt", "w") { |f| f.write "#{parsed_page}" }
puts parsed_page.title
links = parsed_page.css('a')
links.map {|e| e["href"]}
puts links
browser.close
Those last 3 parameters need to be inside a Hash.
browser.cookies.add('openplay_session', value, {path: '/', secure: true, domain: '.openplay.co.uk'})
https://github.com/watir/watir/blob/main/lib/watir/cookies.rb#L40-L55
I am trying to view the JSON request which is sent from POSTMAN through a POST request to add a security group info to a table, and my request looks like one below
POST /securitygroup HTTP/1.1
Host: localhost:9292
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: c4bef1db-d544-c923-3b0b-e7004e2dd093
{
"securitygroup":{
"secgrp_id": 124,
"secgrp_nm": "SECURITY ADMIN",
"secgrp_profile_nme": "ADMIN"
}
}
Roda code looks like below
# cat config.ru
require "roda"
require "sequel"
require "oci8"
require "json"
DB = Sequel.oracle(host: 'xyz.dev.com', port: '1525', database: 'devbox1', user: 'abc', password: 'pass')
class App < Roda
plugin :json, classes: [Array, Hash, Sequel::Model, Sequel::Dataset]
route do |r|
# secgroup = DB[:security_groups]
# secgroup.insert(r.params["securitygroup"])
# secgroup
# above insert threw the following error
# OCIError: ORA-00947: not enough values,
# because SQL generated as below
# INSERT INTO "SECURITYGROUPS" VALUES (NULL)
# so I am trying to access the request object 'r', I feel that I am doing
# something which is not correct
{"response": r.params.["securitygroup"]["secgrp_id"]}
# throws undefined method `[]' for nil:NilClass
end
end
Can you please take a look at the request and point me, where am I going wrong, Request format not correct or is there a different way to handle the request on the ruby code.
I need help to parse the request that comes in as JSON similar to code presented in https://twin.github.io/introduction-to-roda/
r.post "albums" do
album = Album.create(r.params["album"])
r.redirect album_path(album) # /albums/1
end
You need just a little tweak: Add to the App the plugin :json_parser.
class App < Roda
# use this plugin to convert response to json
plugin :json
# use this plugin to convert request from json
plugin :json_parser
...
end
See in the Roda documentation "Plugins that Ship with Roda" in the group "others" there is the json_parser plugin.
I need to change a cookie from "Session" type to "Persistent" type. Moreover I need to have it working together with "omniauth-facebook". In the example below everything is working well but when I use omniauth the cookie is not set at all. This is the test code I wrote:
require 'rubygems'
require 'sinatra'
require 'encrypted_cookie'
require 'omniauth-facebook'
use Rack::Session::EncryptedCookie, :secret => "fdstopitot9dasdsdasjm4kmt0èu54cmjff83d2'ìel.4j9c"
use OmniAuth::Builder do
provider :facebook, '290594154312564','a26bcf9d7e254db82566f31c9d72c94e'
end
get "/" do
"persistent | session | /auth/facebook"
end
get "/persistent" do
response.set_cookie 'test', {:value=> "persistent", :max_age => 2592000.to_s}
redirect "/"
end
get "/session" do
response.set_cookie 'test', {:value=> "session"}
redirect "/"
end
get '/auth/:provider/callback' do
response.set_cookie 'test', {:value=> "facebook_callback"}
redirect "/"
end
Clicking on /session or /persistent you can see the cookie changing accordingly (in Chrome you can check cookies with F12 > Resources > Cookies > localhost).
Clicking instead on /auth/facebook the cookie is not set at all.
The response header seems ok (in Chrome you can see the http response header with F12 > Network > header). I only tested it with Chrome.
HTTP/1.1 302 Moved Temporarily
X-Frame-Options: SAMEORIGIN
Location: http://localhost:4567/
X-XSS-Protection: 1; mode=block
Content-Type: text/html;charset=utf-8
Content-Length: 0
Set-Cookie: test=facebook_callback
Set-Cookie: rack.session=X8U8kupLYzIurjMS4pSCQfF%2BzPpjQhJMqyMd84o8BQdQLwmhagL1UkZ4oi7%2F%0A9bEN%2B0FZDDUAeQD%2BRizczwvepQi%2FbcMwaAjpkFcXhiWuJPQ%3D%0A; path=/
X-Content-Type-Options: nosniff
Connection: keep-alive
Server: thin 1.5.1 codename Straight Razor
Any clue?
Is was a trivial problem, just add the path to the cookie: response.set_cookie 'test', {:value=> "facebook_callback", :path => "/"}
The reason why I did not notice was that there is a redirect to "/", so Chrome was only showing me the cookies for the path "/". Removing the redirect, I notice I have two cookies named "test". One with "/" path and the other with "/auth" path.
I want to be able to parse raw cookie strings in ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin10.8.0].
The CGI::Cookie library looked promising, however, it does not work how I thought it might have.
For example,
CGI::Cookie::parse("ASPSESSIONIDSCDRSRTS=HHALOHOBJGJMLPIANNLDOMCJ; path=/").each_key {|name| p 'Cookie name: ' + name}
Will return:
"Cookie name: ASPSESSIONIDSCDRSRTS"
"Cookie name: path"
What I would like is something like the CGI::new instance works, except you pass it a raw cookie string:
cookie1 = CGI::Cookie::new('name' => 'name',
'value' => ['value1', 'value2', ...],
'path' => 'path', # optional
'domain' => 'domain', # optional
'expires' => Time.now, # optional
'secure' => true # optional
)
name = cookie1.name
values = cookie1.value
path = cookie1.path
domain = cookie1.domain
expires = cookie1.expires
secure = cookie1.secure
What I can't figure out is how to do this eloquently from a raw cookie string.
EDIT ---
The following code is in the ~/.rvm/src/ruby-1.9.3-p194/lib/cgi/cookie.rb file. So it should return as commented below cookies[name] = Cookie::new(name, *values). Which I on't seem to be getting.
# Parse a raw cookie string into a hash of cookie-name=>Cookie
# pairs.
#
# cookies = CGI::Cookie::parse("raw_cookie_string")
# # { "name1" => cookie1, "name2" => cookie2, ... }
#
def Cookie::parse(raw_cookie)
cookies = Hash.new([])
return cookies unless raw_cookie
raw_cookie.split(/[;,]\s?/).each do |pairs|
name, values = pairs.split('=',2)
next unless name and values
name = CGI::unescape(name)
values ||= ""
values = values.split('&').collect{|v| CGI::unescape(v,##accept_charset) }
if cookies.has_key?(name)
values = cookies[name].value + values
end
cookies[name] = Cookie::new(name, *values)
end
cookies
end
EDIT ---
This seems to be a bug in Ruby's CGI::Cookie.parse method. I've opened a bug report on the Ruby bug tracker - https://bugs.ruby-lang.org/issues/7364
I was just having the same problem. CGI::Cookie.new is just not capable to consume what CGI::Cookie::parse produces, they just don't seem to complement each other the way we expected then.
Searching through the gems quickly I found https://github.com/dwaite/cookiejar . It seems this gem tries to do a lot, but least it has code to properly parse raw cookies as we expect it. I didn't try to understand the library because it seems it does so much stuff and I'm actually only concerned about "consuming cookie -> modiyfing it -> produces cookie".
I came up with this quick hack:
require 'cgi'
require 'cookiejar'
# Some sample
raw_cookie = "somecookie=some%7Cvalue; expires=Wed, 02 Apr 2014 13:36:50 GMT; path=/; domain=.somedomain.com"
parts = CookieJar::CookieValidation.parse_set_cookie raw_cookie
# Needs manual unescape
parts[:value] = CGI::unescape(parts[:value])
# Per spec, this name is different
parts[:expires] = parts[:expires_at]
# Remove old ones
parts.delete :expires_at
# CookieJar adds them always, remove
parts.delete :version
# Convert symbol keys to strings for GGI::Cookie
cookie = parts.inject(Hash.new) do |acc, (k,v)|
acc[k.to_s] = v
acc
end
puts CGI::Cookie.new(cookie).to_s
#=> somecookie=some%7Cvalue; domain=.somedomain.com; path=/; expires=Wed, 02 Apr 2014 13:36:50 GMT
I guess that should be a call for a gem which does only one thing with cookies and does it well: being able to parse and generate raw cookie strings. But TBH, the problem domain is probably much more complex then fooling around the way I did.
I haven't used the library, but according to the Ruby docs ( http://www.ruby-doc.org/stdlib-1.9.3/libdoc/cgi/rdoc/CGI/Cookie.html ) what you're calling |name| in your block is actually a Cookie object.
parse(raw_cookie)
Parse a raw cookie string into a hash of cookie-name=>Cookie pairs.
You're probably just seeing the name printed out as that's what an implicit .to_s will give you on a Cookie.
Try printing name.path or name.value (or any of the accessors of a Cookie object) instead.
I'm trying to integrate the Rack OAuth-2 server into my sinatra application, to use it in a web-server flow implementation and I can't make it work :(. I the following code in the oauth controller
require "rack/oauth2/sinatra"
module RestKit
module Network
class OAuth2 < Sinatra::Base
use Rack::Logger
set :sessions, true
set :show_exceptions, true
ENV["DB"] = "test"
DATABASE = Mongo::Connection.new[ENV["DB"]]
register Rack::OAuth2::Sinatra
oauth.authenticator = lambda do |username, password|
"Batman" if username == "cowbell" && password == "more" end
oauth.host = "localhost"
oauth.database = DATABASE
# 3. Obtaining End-User Authorization
before "/oauth/*" do
halt oauth.deny! if oauth.scope.include?("time-travel") # Only Superman can do that
end
get "/oauth/authorize" do
"client: #{oauth.client.display_name}\nscope: #{oauth.scope.join(", ")}\nauthorization: #{oauth.authorization}"
end
post "/oauth/grant" do
oauth.grant! "Batman"
end
post "/oauth/deny" do
oauth.deny!
end
# 5. Accessing a Protected Resource
before { #user = oauth.identity if oauth.authenticated? }
oauth_required "/user"
get "/user" do
#user
end
get "/list_tokens" do
oauth.list_access_tokens("Batman").map(&:token).join(" ")
end
end
end
end
Then I try to obtain an authorization code using curl from terminal with:
curl -i http://localhost:4567/oauth/authorize -F response_type=code -F client_id=[the ID] -F client_secret=[the secret] -F redirect_uri=http://localhost:4567/oauth/showcode
and Just I got as a response:
HTTP/1.1 400 Bad Request
Content-Type: text/plain
Content-Length: 20
Connection: keep-alive
Server: thin 1.2.11 codename Bat-Shit Crazy
Missing redirect URL
Do you have any ideas what I'm doing wrong? Thanks!
The end of your curl request is:
-F redirect_uri=http://localhost:4567/oauth/showcode
but you haven't defined that route in the code above, i.e. where is:
get "/oauth/showcode" do
? That's why the error is "Missing redirect URL".