Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
open-source
MetaGer
Commits
d4e133d3
Commit
d4e133d3
authored
Nov 27, 2019
by
Dominik Hebeler
Browse files
Humanverification now uses Cache functionality
parent
d2714c3d
Changes
5
Hide whitespace changes
Inline
Side-by-side
app/Http/Controllers/HumanVerification.php
View file @
d4e133d3
...
...
@@ -6,7 +6,7 @@ use Captcha;
use
Carbon
;
use
Illuminate\Hashing\BcryptHasher
as
Hasher
;
use
Illuminate\Http\Request
;
use
Illuminate\Support\Facades\
Redis
;
use
Illuminate\Support\Facades\
Cache
;
use
Input
;
class
HumanVerification
extends
Controller
...
...
@@ -15,25 +15,24 @@ class HumanVerification extends Controller
const
EXPIRELONG
=
60
*
60
*
24
*
14
;
const
EXPIRESHORT
=
60
*
60
*
72
;
public
static
function
captcha
(
Request
$request
,
Hasher
$hasher
,
$id
,
$url
=
null
)
public
static
function
captcha
(
Request
$request
,
Hasher
$hasher
,
$id
,
$uid
,
$url
=
null
)
{
$redis
=
Redis
::
connection
(
'redisCache'
);
if
(
$url
!=
null
)
{
$url
=
base64_decode
(
str_replace
(
"<<SLASH>>"
,
"/"
,
$url
));
}
else
{
$url
=
$request
->
input
(
'url'
);
}
$userlist
=
Cache
::
get
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
[]);
$user
=
null
;
if
(
sizeof
(
$userlist
)
===
0
||
empty
(
$userlist
[
$uid
]))
{
return
redirect
(
'/'
);
}
else
{
$user
=
$userlist
[
$uid
];
}
if
(
$request
->
getMethod
()
==
'POST'
)
{
$user
=
$redis
->
hgetall
(
HumanVerification
::
PREFIX
.
"."
.
$id
);
$user
=
[
'uid'
=>
$user
[
"uid"
],
'id'
=>
$user
[
"id"
],
'unusedResultPages'
=>
intval
(
$user
[
"unusedResultPages"
]),
'whitelist'
=>
filter_var
(
$user
[
"whitelist"
],
FILTER_VALIDATE_BOOLEAN
),
'locked'
=>
filter_var
(
$user
[
"locked"
],
FILTER_VALIDATE_BOOLEAN
),
"lockedKey"
=>
$user
[
"lockedKey"
],
];
$lockedKey
=
$user
[
"lockedKey"
];
$key
=
$request
->
input
(
'captcha'
);
...
...
@@ -41,11 +40,11 @@ class HumanVerification extends Controller
if
(
!
$hasher
->
check
(
$key
,
$lockedKey
))
{
$captcha
=
Captcha
::
create
(
"default"
,
true
);
$pipeline
=
$redis
->
pipeline
();
$pipeline
->
hset
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
'lockedKey'
,
$captcha
[
"key"
]);
$pipeline
->
expire
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
$user
[
"whitelist"
]
?
HumanVerification
::
EXPIRELONG
:
HumanVerification
::
EXPIRESHORT
);
$pipeline
->
execute
();
$user
[
"lockedKey"
]
=
$captcha
[
"key"
];
HumanVerification
::
saveUser
(
$user
);
return
view
(
'humanverification.captcha'
)
->
with
(
'title'
,
'Bestätigung notwendig'
)
->
with
(
'uid'
,
$user
[
"uid"
])
->
with
(
'id'
,
$id
)
->
with
(
'url'
,
$url
)
->
with
(
'image'
,
$captcha
[
"img"
])
...
...
@@ -54,13 +53,11 @@ class HumanVerification extends Controller
# If we can unlock the Account of this user we will redirect him to the result page
if
(
$user
!==
null
&&
$user
[
"locked"
])
{
# The Captcha was correct. We can remove the key from the user
# If the sum of all users with that ip is too high we need to whitelist the user or they will receive a captcha again on the next request
$sum
=
0
;
$users
=
[];
$pipeline
=
$redis
->
pipeline
();
$pipeline
->
hmset
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
[
'locked'
=>
"0"
,
'lockedKey'
=>
""
,
'whitelist'
=>
'1'
]);
$pipeline
->
expire
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
$user
[
"whitelist"
]
?
HumanVerification
::
EXPIRELONG
:
HumanVerification
::
EXPIRESHORT
);
$pipeline
->
execute
();
# Additionally we will whitelist him so he is not counted towards botnetwork
$user
[
"locked"
]
=
false
;
$user
[
"lockedKey"
]
=
""
;
$user
[
"whitelist"
]
=
true
;
HumanVerification
::
saveUser
(
$user
);
return
redirect
(
$url
);
}
else
{
return
redirect
(
'/'
);
...
...
@@ -68,11 +65,11 @@ class HumanVerification extends Controller
}
}
$captcha
=
Captcha
::
create
(
"default"
,
true
);
$pipeline
=
$redis
->
pipeline
();
$pipeline
->
hset
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
'lockedKey'
,
$captcha
[
"key"
]);
$pipeline
->
expire
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
$user
[
"whitelist"
]
?
HumanVerification
::
EXPIRELONG
:
HumanVerification
::
EXPIRESHORT
);
$pipeline
->
execute
();
$user
[
"lockedKey"
]
=
$captcha
[
"key"
];
HumanVerification
::
saveUser
(
$user
);
return
view
(
'humanverification.captcha'
)
->
with
(
'title'
,
'Bestätigung notwendig'
)
->
with
(
'uid'
,
$user
[
"uid"
])
->
with
(
'id'
,
$id
)
->
with
(
'url'
,
$url
)
->
with
(
'image'
,
$captcha
[
"img"
]);
...
...
@@ -104,9 +101,38 @@ class HumanVerification extends Controller
return
redirect
(
$url
);
}
private
static
function
saveUser
(
$user
)
{
$userList
=
Cache
::
get
(
HumanVerification
::
PREFIX
.
"."
.
$user
[
"id"
],
[]);
$userList
[
$user
[
"uid"
]]
=
$user
;
if
(
$user
[
"whitelist"
])
{
$user
[
"expiration"
]
=
now
()
->
addWeeks
(
2
);
}
else
{
$user
[
"expiration"
]
=
now
()
->
addHours
(
72
);
}
Cache
::
put
(
HumanVerification
::
PREFIX
.
"."
.
$user
[
"id"
],
$userList
,
now
()
->
addWeeks
(
2
));
}
private
static
function
deleteUser
(
$user
)
{
$userList
=
Cache
::
get
(
HumanVerification
::
PREFIX
.
"."
.
$user
[
"id"
],
[]);
$newUserList
=
[];
$changed
=
false
;
foreach
(
$userList
as
$uid
=>
$userTmp
)
{
if
(
$userTmp
[
"uid"
]
!==
$user
[
"uid"
])
{
$newUserList
[
$userTmp
[
"uid"
]]
=
$userTmp
;
}
else
{
$changed
=
true
;
}
}
if
(
$changed
)
{
Cache
::
put
(
HumanVerification
::
PREFIX
.
"."
.
$user
[
"id"
],
$userList
,
now
()
->
addWeeks
(
2
));
}
}
private
static
function
removeUser
(
$request
,
$uid
)
{
$redis
=
Redis
::
connection
(
'redisCache'
);
$ip
=
$request
->
ip
();
$id
=
""
;
if
(
HumanVerification
::
couldBeSpammer
(
$ip
))
{
...
...
@@ -115,60 +141,34 @@ class HumanVerification extends Controller
$id
=
hash
(
"sha512"
,
$ip
);
}
$userList
=
$redis
->
smembers
(
HumanVerification
::
PREFIX
.
"."
.
$id
);
$pipe
=
$redis
->
pipeline
();
foreach
(
$userList
as
$userid
)
{
$pipe
->
hgetall
(
HumanVerification
::
PREFIX
.
"."
.
$userid
);
$userlist
=
Cache
::
get
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
[]);
$user
=
null
;
if
(
sizeof
(
$userlist
)
===
0
||
empty
(
$userlist
[
$uid
]))
{
return
;
}
else
{
$user
=
$userlist
[
$uid
];
}
$usersData
=
$pipe
->
execute
();
$user
=
[];
$users
=
[];
$sum
=
0
;
foreach
(
$usersData
as
$userTmp
)
{
if
(
empty
(
$userTmp
))
{
continue
;
}
$userNew
=
[
'uid'
=>
$userTmp
[
"uid"
],
'id'
=>
$userTmp
[
"id"
],
'unusedResultPages'
=>
intval
(
$userTmp
[
"unusedResultPages"
]),
'whitelist'
=>
filter_var
(
$userTmp
[
"whitelist"
],
FILTER_VALIDATE_BOOLEAN
),
'locked'
=>
filter_var
(
$userTmp
[
"locked"
],
FILTER_VALIDATE_BOOLEAN
),
"lockedKey"
=>
$userTmp
[
"lockedKey"
],
];
if
(
$uid
===
$userTmp
[
"uid"
])
{
$user
=
$userNew
;
}
else
{
$users
[]
=
$userNew
;
}
if
(
$userNew
[
"whitelist"
])
{
foreach
(
$userlist
as
$uidTmp
=>
$userTmp
)
{
if
(
!
empty
(
$userTmp
)
&&
!
empty
(
$userTmp
[
"whitelist"
])
&&
!
$userTmp
[
"whitelist"
])
{
$sum
+=
intval
(
$userTmp
[
"unusedResultPages"
]);
}
}
if
(
empty
(
$user
))
{
return
;
}
$pipeline
=
$redis
->
pipeline
();
# Check if we have to whitelist the user or if we can simply delete the data
if
(
$user
[
"unusedResultPages"
]
<
$sum
&&
!
$user
[
"whitelist"
])
{
# Whitelist
$pipeline
->
hset
(
HumanVerification
::
PREFIX
.
"."
.
$uid
,
'whitelist'
,
"1"
);
$user
[
"whitelist"
]
=
true
;
}
if
(
$user
[
"whitelist"
])
{
$pipeline
->
hset
(
HumanVerification
::
PREFIX
.
"."
.
$uid
,
'unusedResultPages'
,
"0"
);
$user
[
"unusedResultPages"
]
=
0
;
HumanVerification
::
saveUser
(
$user
);
}
else
{
$pipeline
->
del
(
HumanVerification
::
PREFIX
.
"."
.
$uid
);
$pipeline
->
srem
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
$uid
);
HumanVerification
::
deleteUser
(
$user
);
}
$pipeline
->
expire
(
HumanVerification
::
PREFIX
.
"."
.
$uid
,
$user
[
"whitelist"
]
?
HumanVerification
::
EXPIRELONG
:
HumanVerification
::
EXPIRESHORT
);
$pipeline
->
expire
(
HumanVerification
::
PREFIX
.
"."
.
$id
,
HumanVerification
::
EXPIRELONG
);
$pipeline
->
execute
();
}
private
static
function
checkId
(
$request
,
$id
)
...
...
app/Http/Middleware/HumanVerification.php
View file @
d4e133d3
...
...
@@ -6,7 +6,7 @@ use Captcha;
use
Closure
;
use
Cookie
;
use
Illuminate\Http\Response
;
use
Illuminate\Support\Facades\
Redis
;
use
Illuminate\Support\Facades\
Cache
;
use
URL
;
class
HumanVerification
...
...
@@ -24,7 +24,6 @@ class HumanVerification
$user
=
null
;
$update
=
true
;
$prefix
=
"humanverification"
;
$redis
=
Redis
::
connection
(
'redisCache'
);
try
{
$ip
=
$request
->
ip
();
$id
=
""
;
...
...
@@ -50,56 +49,35 @@ class HumanVerification
}
# Get all Users of this IP
$userList
=
$redis
->
smembers
(
$prefix
.
"."
.
$id
);
$pipe
=
$redis
->
pipeline
();
foreach
(
$userList
as
$userid
)
{
$pipe
->
hgetall
(
$prefix
.
"."
.
$userid
);
}
$usersData
=
$pipe
->
execute
();
$users
=
Cache
::
get
(
$prefix
.
"."
.
$id
,
[]);
$users
=
$this
->
removeOldUsers
(
$users
);
$user
=
[];
$users
=
[];
# Lock out everyone in a Bot network
# Find out how many requests this IP has made
$sum
=
0
;
foreach
(
$usersData
as
$index
=>
$userTmp
)
{
if
(
empty
(
$userTmp
))
{
// This is a key that has been expired and should be deleted
$redis
->
srem
(
$prefix
.
"."
.
$id
,
$userList
[
$index
]);
continue
;
}
$userNew
=
[
'uid'
=>
$userTmp
[
"uid"
],
'id'
=>
$userTmp
[
"id"
],
'unusedResultPages'
=>
intval
(
$userTmp
[
"unusedResultPages"
]),
'whitelist'
=>
filter_var
(
$userTmp
[
"whitelist"
],
FILTER_VALIDATE_BOOLEAN
),
'locked'
=>
filter_var
(
$userTmp
[
"locked"
],
FILTER_VALIDATE_BOOLEAN
),
"lockedKey"
=>
$userTmp
[
"lockedKey"
],
];
if
(
$uid
===
$userTmp
[
"uid"
])
{
$user
=
$userNew
;
}
else
{
$users
[]
=
$userNew
;
}
if
(
!
$userNew
[
"whitelist"
])
{
$sum
+=
intval
(
$userTmp
[
"unusedResultPages"
]);
}
}
# If this user doesn't have an entry we will create one
if
(
empty
(
$user
))
{
$user
=
[
if
(
empty
(
$users
[
$uid
]))
{
$user
=
[
'uid'
=>
$uid
,
'id'
=>
$id
,
'unusedResultPages'
=>
0
,
'whitelist'
=>
false
,
'locked'
=>
false
,
"lockedKey"
=>
""
,
"expiration"
=>
now
()
->
addWeeks
(
2
),
];
}
else
{
$user
=
$users
[
$uid
];
}
# Lock out everyone in a Bot network
# Find out how many requests this IP has made
$sum
=
0
;
// Defines if this is the only user using that IP Adress
$alone
=
true
;
foreach
(
$users
as
$uid
=>
$userTmp
)
{
if
(
!
$userTmp
[
"whitelist"
])
{
$sum
+=
$userTmp
[
"unusedResultPages"
];
if
(
$userTmp
[
"uid"
]
!=
$uid
)
{
$alone
=
false
;
}
}
}
# A lot of automated requests are from websites that redirect users to our result page.
...
...
@@ -116,14 +94,6 @@ class HumanVerification
}
// Defines if this is the only user using that IP Adress
$alone
=
true
;
foreach
(
$users
as
$userTmp
)
{
if
(
$userTmp
[
"uid"
]
!=
$uid
&&
!
$userTmp
[
"whitelist"
])
{
$alone
=
false
;
}
}
if
((
!
$alone
&&
$sum
>=
50
&&
!
$user
[
"whitelist"
])
||
$refererLock
)
{
$user
[
"locked"
]
=
true
;
}
...
...
@@ -136,7 +106,8 @@ class HumanVerification
new
Response
(
view
(
'humanverification.captcha'
)
->
with
(
'title'
,
"Bestätigung erforderlich"
)
->
with
(
'id'
,
$uid
)
->
with
(
'uid'
,
$uid
)
->
with
(
'id'
,
$id
)
->
with
(
'url'
,
url
()
->
full
())
->
with
(
'image'
,
$captcha
[
"img"
])
);
...
...
@@ -156,31 +127,14 @@ class HumanVerification
}
}
}
catch
(
\
Predis\Connection\ConnectionException
$e
)
{
$update
=
false
;
}
finally
{
if
(
$update
)
{
// Update the user in the database
$pipeline
=
$redis
->
pipeline
();
$pipeline
->
hmset
(
$prefix
.
"."
.
$user
[
'uid'
],
$user
);
$pipeline
->
sadd
(
$prefix
.
"."
.
$user
[
"id"
],
$user
[
"uid"
]);
// Expire in two weeks
$expireLong
=
60
*
60
*
24
*
14
;
// Expire in 72h
$expireShort
=
60
*
60
*
72
;
if
(
$user
[
"whitelist"
])
{
$
pipeline
->
expire
(
$prefix
.
"."
.
$user
[
'uid'
],
$expireLong
);
$
user
[
"expiration"
]
=
now
()
->
addWeeks
(
2
);
}
else
{
$
pipeline
->
expire
(
$prefix
.
"."
.
$user
[
'uid'
],
$expireShort
);
$
user
[
"expiration"
]
=
now
()
->
addHours
(
72
);
}
$pipeline
->
expire
(
$prefix
.
"."
.
$user
[
"id"
],
$expireLong
);
$pipeline
->
execute
();
$this
->
setUser
(
$prefix
,
$user
);
}
}
...
...
@@ -188,4 +142,38 @@ class HumanVerification
return
$next
(
$request
);
}
public
function
setUser
(
$prefix
,
$user
)
{
// Lock must be acquired within 2 seconds
$userList
=
Cache
::
get
(
$prefix
.
"."
.
$user
[
"id"
],
[]);
$userList
[
$user
[
"uid"
]]
=
$user
;
Cache
::
put
(
$prefix
.
"."
.
$user
[
"id"
],
$userList
,
now
()
->
addWeeks
(
2
));
}
public
function
removeOldUsers
(
$userList
)
{
$newUserlist
=
[];
$now
=
now
();
$id
=
""
;
$changed
=
false
;
foreach
(
$userList
as
$uid
=>
$user
)
{
$id
=
$user
[
"id"
];
if
(
$now
<
$user
[
"expiration"
])
{
$newUserlist
[
$user
[
"uid"
]]
=
$user
;
}
else
{
$changed
=
true
;
}
}
if
(
$changed
)
{
// Lock must be acquired within 2 seconds
Cache
::
lock
(
$prefix
.
"."
.
$user
[
"id"
])
->
block
(
2
,
function
()
{
Cache
::
put
(
$prefix
.
"."
.
$user
[
"id"
],
$newUserlist
,
now
()
->
addWeeks
(
2
));
});
}
return
$newUserlist
;
}
}
config/database.php
View file @
d4e133d3
...
...
@@ -135,13 +135,6 @@ return [
'port'
=>
env
(
'REDIS_PORT'
,
6379
),
'database'
=>
0
,
],
'redisCache'
=>
[
'host'
=>
env
(
'REDIS_CACHE_HOST'
,
'localhost'
),
'password'
=>
env
(
'REDIS_CACHE_PASSWORD'
,
env
(
'REDIS_PASSWORD'
,
null
)),
'port'
=>
env
(
'REDIS_CACHE_PORT'
,
6379
),
'database'
=>
2
,
],
],
];
resources/views/humanverification/captcha.blade.php
View file @
d4e133d3
...
...
@@ -7,8 +7,9 @@
<
p
>@
lang
(
'captcha.2'
)
</
p
>
<
p
>@
lang
(
'captcha.3'
)
</
p
>
<
p
>@
lang
(
'captcha.4'
)
</
p
>
<
form
method
=
"post"
action
=
"{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), route('verification', ['id' =>
$id
])) }}"
>
<
form
method
=
"post"
action
=
"{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), route('verification', ['id' =>
$id
, 'uid' =>
$uid
])) }}"
>
<
input
type
=
"hidden"
name
=
"url"
value
=
"{!!
$url
!!}"
>
<
input
type
=
"hidden"
name
=
"uid"
value
=
"{{
$uid
}}"
>
<
input
type
=
"hidden"
name
=
"id"
value
=
"{{
$id
}}"
>
<
p
><
img
src
=
"{{
$image
}}"
/></
p
>
@
if
(
isset
(
$errorMessage
))
...
...
routes/session.php
View file @
d4e133d3
...
...
@@ -6,6 +6,6 @@ Route::group(
'middleware' => [ 'localeSessionRedirect', 'localizationRedirect' ]*/
],
function
()
{
Route
::
match
([
'get'
,
'post'
],
'meta/verification/{id}/{url?}'
,
'HumanVerification@captcha'
)
->
name
(
'verification'
);
Route
::
match
([
'get'
,
'post'
],
'meta/verification/{id}/{
uid}/{
url?}'
,
'HumanVerification@captcha'
)
->
name
(
'verification'
);
}
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment