I have looked for an answer in an existing question, but found nothing which covers this hashing scheme in Rails.
I am currently migrating a PHP project over to Ruby-on-Rails, which I am still learning. I am struggling to port over an MD5 (I know, it's only temporary...) hashing scheme for hashing user passwords. I have plain MD5 working, but cannot find the correct syntax for the hashing scheme I need.
The mechanics of the hashing scheme in the PHP project are:
Create MD5 hash of password.
Create MD5 hash of salt.
Concatenate password_hash with salt_hash.
Create MD5 hash of concatenated_string.
Compare stored_hash to concatenated_string
The PHP for the hash creation is:
function fn_generate_salted_password($password, $salt)
{
$_pass = '';
if (empty($salt)) {
$_pass = md5($password);
} else {
$_pass = md5(md5($password) . md5($salt));
}
return $_pass;
}
The (pathetic) attempt I have for this section in Rails so far is:
Spree::User.class_eval do
def valid_password?(password)
if self.salt.present
if ::Digest::MD5.hexdigest((::Digest::MD5.hexdigest(password)).(::Digest::MD5.hexdigest(salt))) == self.stored_hash
*# Do some stuff*
else
false
end
end
end
end
Any ideas?
I would do something like this:
def valid_password?(password)
secret = if salt.present?
[password, salt].map { |part| ::Digest::MD5.hexdigest(part) }.join
else
password
end
stored_hash == ::Digest::MD5.hexdigest(secret)
end
Related
In my Rails-api app I'am using Devise gem which when authenticating returns all crucial info (Access-Token, UID, Client etc) in Headers, like this:
Access-Token →DIbgreortZbCYKqzC8HdNg
Client →Y6J5oTIqS7Gc_-h9xynBQ
Uid →email2#example.com
I want those to be in the response Body. Is there any way to achieve this?
Rails provides you with a request object so you can grab whatever you need out of the headers in your controller.
def some_action
#mime_type = request.headers["Content-Type"] # => "text/plain"
#token = request.headers["key-for-your-token-here"]
end
You can then either pass it to your view or you can insert it into the response body via request.bodyas you would insert any key/value pair into a hash.
Documentation for ActionDispatch::Request found here:
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
UPDATE:
Make a custom method and see how long it has to run to navigate the header hash. If long you can use it to find the exact nesting of what you're looking for and change it.
def find_token(parent, request.headers)
request.headers.each {|key, value|
if value.is_a?(Hash)
find_token(key, value)
elsif key == 'THE TOKEN KEY HERE'
return value
else
next
end
}
end
my users have the option to add their website, facebook and twitter URL's to their profile.
I want to let them enter either the full URL (http://www.facebook.com/USERNAME) or part of the URL Eg. www.facebook.com/USERNAME or just USERNAME, and then have the https://facebook.com/ added automatically if needed. I want the http:// as then the entered URL will link directly to their website/facebook etc.
For the website URL I have:
before_validation :add_url_protocol
def add_url_protocol
if self.website && !url_protocol_present?
self.website = "http://#{self.website}"
end
end
def url_protocol_present?
self.website[/\Ahttp:\/\//] || self.website[/\Ahttps:\/\//]
end
There is then further regex validation.
This works fine.
The thing is I don't have much of an idea about regex and I am unsure on how to add the facebook.com/ part to this before_validation code.
Any help would be greatly appreciated, thanks.
UPDATE:
def add_url_protocol
if self.website && !url_protocol_present?
self.website = "http://#{self.website}"
end
if self.facebook && !url_facebook_present?
self.facebook = "http://facebook.com/#{self.facebook}"
end
end
This almost works. If a user inputs USERNAME then the output is good. If the user inputs www.facebook.com/USERNAME then the ouput becomes http://facebook.com/www.facebook.com/USERNAME
The best way to do this would be to collect user input in a form model, you can roll your own with by including ActiveModel::Model or use something like Reform.
The easiest thing you can do is simply treat their input as a string containing their facebook username separated by "/" so whatever the string they enter you can get the username by
"https://www.facebook.com/their.username".split('/')[-1] # 'their.username'
"www.facebook.com/their.username".split('/')[-1] # 'their.username'
"their.username".split('/')[-1] # 'their.username'
Simply declare a username attribute in your form model and overwrite the setter to extract the facebook username. Then only save the facebook username in your database, and write a method such as
def facebook_profile_url
"www.facebook.com/#{fb_username}"
end
No need to persist the redundant facebook url part.
I would try
match = /^(https?:\/\/)?((www\.)?facebook\.com)?(.*)/.match(self.website)
self.website = match[1] || 'http://'
self.website << match[2] || 'facebook.com'
self.website << match[3]
You can create capture groups by using parentheses. The ? means that group or char before it is optional (so I was able to condense your protocol search)
You may need to check my indexes into the match array...
Sorry this is untested as it is from a phone...
IE10 is returning parameters in what looks like a double conversion to JSON :
=> {"{\"statementId\":"=>
{"\"b3dsecret9-bsecret741-23secreta806c\""=>
{",\"Content-Type\":"=>
{"\"application/json\""=>
{",\"content\":"=>
{"\"{\\\"context\\\":{\\\"registration\\\":\\\"27\\\",\\\"contextActivities\\\":{\\\"parent\\\":{\\\"id\\\":\\\"6LHIJumrnmV_course_id\\\"},\\\"grouping\\\":{\\\"id\\\":\\\"6LHIJumrnmV_course_id\\\"}}},\\\"actor\\\":213,\\\"verb\\\":\\\"attempted\\\",\\\"object\\\":{\\\"id\\\":\\\"6LHIJumrnmV_course_id\\\",\\\"definition\\\":{\\\"name\\\":{\\\"und\\\":\\\"\\\"},\\\"type\\\":\\\"Course\\\",\\\"description\\\":{\\\"und\\\":\\\"\\\"}}}}\""=>
{",\"registration\":"=>
{"\"27\""=>
{",\"AWSAccessKeyId\":"=>
{"\"secretIAIVsecretPHsecretQ\""=>
{",\"Signature\":"=>
{"\"PJ /OW K5secretasyXsecret5A"=>
"\"],\"Expires\":[\"1396873090\"],\"Authorization\":[\"\"]}"}}}}}}}}}}},
"method"=>"PUT",
"controller"=>"quizzes",
"action"=>"statements"}
IE Edge, Safari, Chrome, and Firefox return my params like this :
=> {"registration"=>["27"],
"Content-Type"=>["application/json"],
"Signature"=>["secretkqPJGPEsecret01ksecret"],
"AWSAccessKeyId"=>["Asecret6secretPHsecretQ"],
"statementId"=>["5919c4f4-b71c-40dd-81dc-ab63cfc824bd"],
"Expires"=>["1396873699"],
"Authorization"=>[""],
"content"=>
["{\"object\":{\"definition\":{\"type\":\"Course\",\"name\":{\"und\":\"\"},\"description\":{\"und\":\"\"}},\"id\":\"6LHIJumrnmV_course_id\"},\"verb\":\"attempted\",\"context\":{\"registration\":\"27\",\"contextActivities\":{\"parent\":{\"id\":\"6LHIJumrnmV_course_id\"},\"grouping\":{\"id\":\"6LHIJumrnmV_course_id\"}}},\"actor\":213}"],
"method"=>"PUT",
"controller"=>"quizzes",
"action"=>"statements",
"quiz"=>{}
So my code parses this conveniently doing this :
content = params[:content] || params['content']
response = JSON.parse(content.first)
And presto! I have a workable piece of content. But with that first aforementioned Hash, I'm not sure how to convert that. Should I just be thinking of using a match/gsub technique to remove all those evil forward slashes? Is there a way to decipher that into something that looks like my latter hash?
Starting from your answer, I would parse key using the escape_utils gem:
require 'escape_utils'
def nested_hash_value(obj,key)
# nested_hash_value(params, ",\"content\":")
if obj.respond_to?(:key?) && obj.key?(key)
obj[key]
elsif obj.respond_to?(:each)
r = nil
obj.find{ |*a| r=nested_hash_value(a.last,key) }
r
end
end
extract = nested_hash_value(params, ",\"content\":")
key = extract.keys.first
response = JSON.parse EscapeUtils.unescape_javascript(key).gsub(/^"|"$/,'')
This avoids using the evil eval thing.
More generally, I think you should build your processing in this way:
def smell_of_ie_weirdness?
# Detects whether the request seems like the one sent by IE 10,
# something like params keys formatting checking etc.
end
def extracted_response
if smell_of_ie_weirdness?
# Do weird stuff
extract_response_for_weird_ie
else
# Be clean and polite
extract_response
end
end
Well this gives me an answer.. it's not the best. It's definitely a hack. But I feel like it's the only thing I got.
def nested_hash_value(obj,key)
# nested_hash_value(params, ",\"content\":")
if obj.respond_to?(:key?) && obj.key?(key)
obj[key]
elsif obj.respond_to?(:each)
r = nil
obj.find{ |*a| r=nested_hash_value(a.last,key) }
r
end
end
extract = nested_hash_value(params, ",\"content\":")
key = extract.keys.first
decoded_hash = key.to_s.gsub(/\\/,'').gsub(/\"/,"'").gsub(/'$|^'/,'').gsub(':','=>')
response = eval decoded_hash
If I do a comparison == between the two outputs they return true .
Then I just throw it all in a rescue block..
begin
content = params[:content] || params['content']
response = JSON.parse(content.first)
rescue
perform_fd_up_IE_fixer # :)
end
I have an algorithm that searches through all of my sites users, finding those which share a common property with the user using the algorithm (by going to a certain page). It can find multiple users, each can have multiple shared properties. The algorithm works fine, in terms of finding the matches, but I'm having trouble working out how to store the data so that later I'll be able to use each unit of information. I need to be able to access both the found users, and each of the respective shared properties, so I can't just build a string. This is an example of the output, being run from the perspective of user 1:
user 4
sharedproperty3
sharedproperty6
user 6
sharedproperty6
sharedproperty10
shareproperty11
What do I need to do to be able to store this data, and have access to any bit of it for further manipulation? I was thinking of a hash of a hash, but I can't really wrap my head around it. I'm pretty new to programming, and Ruby in particular. Thanks for reading!
EDIT - Here's the code. I'm fully expecting this to be the most incorrect way to do this, but it's my first try so be gentle :)
So if I'm understanding you guys correctly, instead of adding the interests to a string, I should be creating an array or a hash, adding each interest as I find it, then storing each of these in an array or hash? Thanks so much for the help.
def getMatchedUsers
matched_user_html = nil
combined_properties = nil
online_user_list = User.logged_in.all
shared_interest = false
online_user_list.each do |n| # for every online user
combined_properties = nil
if n.email != current_user.email # that is not the current user
current_user.properties.each do |o| # go through all of the current users properties
n.properties.each do |p| # go through the online users properties
if p.interestname.eql?(o.interestname) # if the online users property matches the current user
shared_interest = true
if combined_properties == nil
combined_properties = o.interestname
else
combined_properties = combined_properties + ", " + o.interestname
end
end
end
if shared_interest == true
matched_user_html = n.actualname + ": " + combined_properties
end
end
end
end
return matched_user_html
render :nothing => true
end
This returns an array of hashes with all users and their corresponding sharedproperties.
class User
def find_matching_users
returning Array.new do |matching_users|
self.logged_in.each do |other_user|
next if current_user == other_user # jump if current_user
# see http://ruby-doc.org/core/classes/Array.html#M002212 for more details on the & opreator
unless (common_properties = current_user.properties & other_user.properties).empty?
matching_users << { :user => other_user, :common_properties => common_properties }
end
end
end
end
end
In your view you can do something like this:
<%- current_user.find_matching_users.each do |matching_user| -%>
<%-# you can acccess the user with matching_user[:user] -%>
<%-# you can acccess the common properties with matching_user[:common_properties] -%>
<%- end -%>
You can use a hash table with the key being the user object and the value being an array of the shared properties . This is assuming that you first need to do a lookup based on the user .
Something like this :
#user_results = { user1 => [sharedproperty3,sharedproperty7] , user2 => [sharedproperty10,sharedproperty11,sharedproperty12]}
You can then acces the values like :
#user_results[user1]
or you can also iterate over all the keys using #user_results.keys
I have a URL encoded resource such as:
http://myurl/users/Joe%20Bloggs/index.xml
This is for a RESTful webservice which uses user logins in the path. The problem is that the controller in rails doesn't seem to decode the %20. I get the following error:
ActionController::RoutingError (No route matches "/Joe%20Bloggs/index.xml" with {:method=>:post}):
What I'm actually trying to do is achieve one of 2 options (using authlogic as my registrations handler):
Either (preferably) allow users to register user names with spaces in them, and have these get routed correctly to my controller. Authlogic by default allows spaces & #/. characters - which is just fine with me if I can make it work...
Or I can restrict authlogic to dissallow the spaces. I know I can do this with:
.merge_validates_format_of_login_field_options...
but I'm not entirely sure of the correct syntax to provide the new regex and return message on failure...
Any suggestions greatly appreciated!
Generally it's a better idea to have a URL-safe "slug" field in your models for situations like this. For example:
class User < ActiveRecord::Base
before_validation :assign_slug
def to_param
# Can't use alias_method on methods not already defined,
# ActiveRecord creates accessors after DB is connected.
self.slug
end
def unique_slug?
return false if (self.slug.blank?)
if (new_record?)
return self.class.count(:conditions => [ 'slug=?', self.slug ]) == 0
else
return self.class.count(:conditions => [ 'slug=? AND id!=?', self.slug, self.id ]) == 0
end
end
def assign_slug
return if (slug.present?)
base_slug = self.name.gsub(/\s+/, '-').gsub(/[^\w\-]/, '')
self.slug = base_slug
count = 1
# Hunt for a unique slug starting with slug1 .. slugNNN
while (!unique_slug?)
self.slug = base_slug + count.to_s
count += 1
end
end
end
This may solve the problem of having non-URL-friendly names. Rails is particularly ornery when it comes to having dots in the output of to_param.