I'm importing 15000 users from virtuemart into magento but have been unable to get the passwords to import correctly.
My problem is that the passwords are hashed differently.
Virtuemart HASH = md5($password.$salt);
Magento HASH = md5($salt.$password);
An example password looks like:
c957d358c8a79e66af10086b53b5a069:AuHg2mCXUhViqKYCLtFco22rmUCDwIFI
An answer has been provided below which partially solves my problem. Applying this allows my virtuemart customers to login but causes issues with the admin login and forces new users to use the virtuemart password hash format.
I now need to modify this in such a way that it checks the core hashing method, and if that fails it checks the virtuemart hashing method allowing both password formats to login.
I was thinking something along the lines of
public function getHash($password, $salt = false)
{
if (is_integer($salt)) {
$salt = $this->_helper->getRandomString($salt);
}
return $salt === false ? $this->hash($password) : $this->hash($password . $salt) . ':' . $salt : $this->hash($salt . $password) . ':' . $salt;
}
.
public function validateHash($password, $hash)
{
$hashArr = explode(':', $hash);
switch (count($hashArr)) {
case 1:
// no hash
return $this->hash($password) === $hash;
case 2:
// magento default hash
return $this->hash($hashArr[1] . $password) === $hashArr[0];
case 3:
// virtuemart hash
return $this->hash($password . $hashArr[1]) === $hashArr[0]; }
Mage::throwException('Invalid hash.');
}
but as you can probably tell this doesnt work as i have no way to check the hash type method.
How would i go about this please ?
UPDATE - Heres my latest attempt.
public function validateHash($password, $hash)
{
$hashArr = explode(':', $hash);
if(admin_login_handling_and_api_user_accounts){
switch (count($hashArr)) {
case 1:
return $this->hash($password) === $hash;
case 2:
return $this->hash($hashArr[1] . $password) === $hashArr[0];
}
} else if(Magento_customer_handling){
switch (count($hashArr)) {
case 1:
return $this->hash($password) === $hash;
case 2:
return $this->hash($password . $hashArr[1]) === $hashArr[0];
}
} else if(soap_Api_customer_handling){
switch (count($hashArr)) {
case 1:
return $this->hash($password) === $hash;
case 2:
return $this->hash($hashArr[1] . $password) === $hashArr[0];
}
}
}
I've changed the validatehash function to include if statements but this doesnt seem to be recognised. My php skills are on the very basic side so if someone could please explain where im going wrong with this or if theres a better way to go about it.
Thanks.
It all depends how the algorithm works in virtuemart. After a quick google it seems like it takes the password provided by the user and appends the salt (the part after the semi-colon) to the end, then md5's the value, which it compares to the password hash (the part before the semi-colon in the database).
In contrast to that Magento prepends the salt to the start of the password before md5 hashing it, rather than the end.
Long story short, the quick win should be attainable by editing Mage_Core_Model_Encryption::validateHash so that if $hashArr has a count of two it will append the hash, rather than prepend.
// replace
return $this->hash($hashArr[1] . $password) === $hashArr[0];
// with
return $this->hash($password . $hashArr[1]) === $hashArr[0];
Related
This question is very similar to Laravel filter a value in all columns. Sorry, if it turns out as a duplicate later on, but I have another working code to provide.
What does work is filtering on the client side via JavaScript:
filterfunction : function(entry, filter)
{
if(filter != null)
filter.trim().split(' ').forEach(function(item){
if(!this.eachRecursive(entry, item))
return false;
});
return true;
},
eachRecursive: function(obj, localfilter) {
for(const key in obj) {
if (!obj.hasOwnProperty(key))
continue;
if(typeof obj[key] == "object" && obj[key] !== null){
if(this.eachRecursive(obj[key], localfilter))
return true;
}
else
if((obj[key] + "").toLowerCase().indexOf(localfilter.toLowerCase()) != -1)
return true;
}
return false;
},
The filter function is used as the filter function for the Bootstrap-Vue table component like described in custom-filter-function.
The question is now: how to achieve similar functionality in the Laravel-Backend (for using with Livewire)?
I can imagine, that listing all columns via getColumnListing, mentioned in Laravel filter a value in all columns is possible, but this wouldn't suffice, I still need the relations, like in laravel mysql query with multiple where orwhere and inner join.
Currently, I'm trying out to convert the Eloquent object to JSON and then to parse it, as it includes all the loaded relations eloquent-serialization. But this seems like the last resort and a kind of misuse of serialization.
For now I'm going to use the route over converting to json. However, I found a way to not to parse json by regular expressions. Instead, I convert the jsonified collection back to php objects. With them I'm able to reimplement the functions from above:
private function eachRecursive(stdClass $obj, string $localfilter) {
foreach($obj as $key => $val){
if(is_object($val)){
if($this->eachRecursive($val, $localfilter))
return true;
} elseif(is_array($val)){
foreach($val as $k => $v)
if($this->eachRecursive($v, $localfilter))
return true;
} elseif(stripos(strval($val), $localfilter) !== false){
return true;
}
}
return false;
}
private function filterfunction(Collection $collection, string $filter){
$retVal = [];
foreach (json_decode($collection->toJson()) as $entity){
foreach(explode(' ', trim($filter)) as $localfilter)
if(!$this->eachRecursive($entity, $localfilter))
continue 2;
array_push($retVal, $entity->id);
}
return $retVal;
}
I have stored a url in session in laravel. Now i want to compare link between session url which was stored and the url()->previous(). But the problem is url is dynamic.
THe problem i am facing
$url = url('/').'/complete-profile/*';
if(session()->get('url.intended') == $url)
{
return redirect('/home');
}
This doesn't work. how to compare /complete-profile/* with other url.. (*) this can be anything
Try something like this. Builds your URL and the rest check if it contains the word complete-profile :
$url = 'complete-profile';
if (strpos(session()->get('url.intended'), $url) !== false) {
return redirect('/home');
} else {
//
}
I used the script from here to do the verification.
The $result === FALSE condition was being bypassed regardless of me clicking on the re-captcha validation on my form.
So I decided to manually parse it like so:
The return looks like this if a failure:
{
"success":false,
"error-codes":[
"missing-input-response"
]
}
And if it's success it looks similar but some additional things are attached, but the main thing I targeted was the string "success":true,
With this part of the script directly below the $result variable:
$result_copy = $result;
// remove white spaces everywhere
$mod_res_copy = preg_replace('/\s+/', '', $result_copy);
$success_string = '"success":true';
if(strpos($mod_res_copy, $success_string) !== false) {
$status = "ok";
}else {
$status = "not-ok";
}
if ($status == "not-ok") {
echo "Please complete the captcha to prevent spam.";
exit;
}else {
// trigger database insert of comment or whatever
}
What I want to know is, is this wrong? Can this be spoofed? I'm using PHP as my server-side scripting language.
You are doing way more work than you need, to parse $result.
It is in JSON format, so this is all you need:
$status = json_decode($result)->success ? 'ok' : 'not-ok';
Both are working, but I am asking if there is any difference or can I just use redirect(); ?
So from these 3 variants, which one is the one that I should stick to?
redirect('/');
or
redirect('');
or
redirect();
If you look at the source you can see that it appends the given URL to the site_url.
function redirect($uri = '', $method = 'location', $http_response_code = 302)
{
if ( ! preg_match('#^https?://#i', $uri))
{
$uri = site_url($uri);
}
switch($method)
{
case 'refresh' : header("Refresh:0;url=".$uri);
break;
default : header("Location: ".$uri, TRUE, $http_response_code);
break;
}
exit;
}
So like you said, all those options work.
But I would personally recommend to use:
redirect('/');
If you work with multiple developers this is easier to understand for those who are not familiar with CodeIgniter, since most developer know that "/" refers to the "root directory".
I'm hashing the passwords upon account creation, and that it working (with the password set to VARCHAR(60)) but when I try to do this:
$query = $this->CI->db->query("SELECT * FROM users WHERE email = ?", $email);
if ($query->num_rows() > 0) {
$user_pass = $query->row()->password;
$hasher = new PasswordHash(PHPASS_HASH_STRENGTH, PHPASS_HASH_PORTABLE);
if ($hasher->CheckPassword($user_pass, $pass)) {
return true;
} else {
return false;
}
} else {
return false;
}
it always returns false. Any ideas as to why this might be? (the password I'm providing is correct)
I think you have inverted the check password field. It has to be like this:
$hasher->CheckPassword(password which has to be checked, password from database).
This makes a difference because Check Password is going to hash the password which is to be checked.