mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2024-11-25 19:05:53 +03:00
feat: track maximum recorded nonce for captcha levels to render progress bar
This commit is contained in:
parent
49a8757ead
commit
b6497882d7
12 changed files with 356 additions and 0 deletions
|
@ -292,6 +292,21 @@ pub trait MCDatabase: std::marker::Send + std::marker::Sync + CloneSPDatabase {
|
|||
|
||||
/// Get all psuedo IDs
|
||||
async fn analytics_get_all_psuedo_ids(&self, page: usize) -> DBResult<Vec<String>>;
|
||||
|
||||
/// Track maximum nonce received against captcha levels
|
||||
async fn update_max_nonce_for_level(
|
||||
&self,
|
||||
captcha_key: &str,
|
||||
difficulty_factor: u32,
|
||||
latest_nonce: u32,
|
||||
) -> DBResult<()>;
|
||||
|
||||
/// Get maximum nonce tracked so far for captcha levels
|
||||
async fn get_max_nonce_for_level(
|
||||
&self,
|
||||
captcha_key: &str,
|
||||
difficulty_factor: u32,
|
||||
) -> DBResult<u32>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
|
||||
|
|
|
@ -310,6 +310,33 @@ pub async fn database_works<'a, T: MCDatabase>(
|
|||
.unwrap();
|
||||
// analytics end
|
||||
|
||||
// nonce tracking start
|
||||
assert_eq!(
|
||||
db.get_max_nonce_for_level(c.key, l[0].difficulty_factor)
|
||||
.await
|
||||
.unwrap(),
|
||||
0
|
||||
);
|
||||
db.update_max_nonce_for_level(c.key, l[0].difficulty_factor, 1000)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
db.get_max_nonce_for_level(c.key, l[0].difficulty_factor)
|
||||
.await
|
||||
.unwrap(),
|
||||
1000
|
||||
);
|
||||
db.update_max_nonce_for_level(c.key, l[0].difficulty_factor, 10_000)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
db.get_max_nonce_for_level(c.key, l[0].difficulty_factor)
|
||||
.await
|
||||
.unwrap(),
|
||||
10_000
|
||||
);
|
||||
// nonce tracking end
|
||||
|
||||
assert_eq!(db.fetch_solve(p.username, c.key).await.unwrap().len(), 1);
|
||||
assert_eq!(
|
||||
db.fetch_config_fetched(p.username, c.key)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "INSERT INTO\n mcaptcha_track_nonce (level_id, nonce)\n VALUES ((\n SELECT\n level_id\n FROM\n mcaptcha_levels\n WHERE\n config_id = (SELECT config_id FROM mcaptcha_config WHERE captcha_key = ?)\n AND\n difficulty_factor = ?\n AND\n visitor_threshold = ?\n ), ?);",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "216478d53870d7785cd0be43f030883ab79eaafb558d9197d09aea3adbd7b0bc"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "UPDATE mcaptcha_track_nonce SET nonce = ?\n WHERE level_id = (\n SELECT\n level_id\n FROM\n mcaptcha_levels\n WHERE\n config_id = (SELECT config_id FROM mcaptcha_config WHERE captcha_key = ?)\n AND\n difficulty_factor = ?\n )\n AND nonce <= ?;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 4
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "349ba17ff197aca7ee9fbd43e227d181c27ae04702fd6bdb6ddc32aab3bcb1ea"
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "SELECT nonce FROM mcaptcha_track_nonce\n WHERE level_id = (\n SELECT\n level_id\n FROM\n mcaptcha_levels\n WHERE\n config_id = (SELECT config_id FROM mcaptcha_config WHERE captcha_key = ?)\n AND\n difficulty_factor = ?\n );",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "nonce",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 11
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b739ec4cfab1ec60947106c8112e931510c3a50a1606facdde0c0ebb540d5beb"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
-- Add migration script here
|
||||
CREATE TABLE IF NOT EXISTS mcaptcha_track_nonce (
|
||||
level_id INTEGER NOT NULL,
|
||||
nonce INTEGER NOT NULL DEFAULT 0,
|
||||
ID INT auto_increment,
|
||||
PRIMARY KEY(ID),
|
||||
CONSTRAINT `fk_mcaptcha_track_nonce_level_id`
|
||||
FOREIGN KEY (level_id)
|
||||
REFERENCES mcaptcha_levels (level_id)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE
|
||||
);
|
|
@ -433,6 +433,39 @@ impl MCDatabase for Database {
|
|||
futs.push(fut);
|
||||
}
|
||||
|
||||
try_join_all(futs)
|
||||
.await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
||||
let mut futs = Vec::with_capacity(levels.len());
|
||||
|
||||
for level in levels.iter() {
|
||||
let difficulty_factor = level.difficulty_factor as i32;
|
||||
let visitor_threshold = level.visitor_threshold as i32;
|
||||
let fut = sqlx::query!(
|
||||
"INSERT INTO
|
||||
mcaptcha_track_nonce (level_id, nonce)
|
||||
VALUES ((
|
||||
SELECT
|
||||
level_id
|
||||
FROM
|
||||
mcaptcha_levels
|
||||
WHERE
|
||||
config_id = (SELECT config_id FROM mcaptcha_config WHERE captcha_key = ?)
|
||||
AND
|
||||
difficulty_factor = ?
|
||||
AND
|
||||
visitor_threshold = ?
|
||||
), ?);",
|
||||
&captcha_key,
|
||||
difficulty_factor,
|
||||
visitor_threshold,
|
||||
0,
|
||||
)
|
||||
.execute(&self.pool);
|
||||
futs.push(fut);
|
||||
}
|
||||
|
||||
try_join_all(futs)
|
||||
.await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
@ -1087,6 +1120,70 @@ impl MCDatabase for Database {
|
|||
|
||||
Ok(res.drain(0..).map(|r| r.psuedo_id).collect())
|
||||
}
|
||||
|
||||
/// Track maximum nonce received against captcha levels
|
||||
async fn update_max_nonce_for_level(
|
||||
&self,
|
||||
captcha_key: &str,
|
||||
difficulty_factor: u32,
|
||||
latest_nonce: u32,
|
||||
) -> DBResult<()> {
|
||||
let latest_nonce = latest_nonce as i64;
|
||||
sqlx::query!(
|
||||
"UPDATE mcaptcha_track_nonce SET nonce = ?
|
||||
WHERE level_id = (
|
||||
SELECT
|
||||
level_id
|
||||
FROM
|
||||
mcaptcha_levels
|
||||
WHERE
|
||||
config_id = (SELECT config_id FROM mcaptcha_config WHERE captcha_key = ?)
|
||||
AND
|
||||
difficulty_factor = ?
|
||||
)
|
||||
AND nonce <= ?;",
|
||||
latest_nonce,
|
||||
&captcha_key,
|
||||
difficulty_factor as i64,
|
||||
latest_nonce
|
||||
)
|
||||
.execute(&self.pool).await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get maximum nonce tracked so far for captcha levels
|
||||
async fn get_max_nonce_for_level(
|
||||
&self,
|
||||
captcha_key: &str,
|
||||
difficulty_factor: u32,
|
||||
) -> DBResult<u32> {
|
||||
struct X {
|
||||
nonce: i32,
|
||||
}
|
||||
|
||||
let res = sqlx::query_as!(
|
||||
X,
|
||||
"SELECT nonce FROM mcaptcha_track_nonce
|
||||
WHERE level_id = (
|
||||
SELECT
|
||||
level_id
|
||||
FROM
|
||||
mcaptcha_levels
|
||||
WHERE
|
||||
config_id = (SELECT config_id FROM mcaptcha_config WHERE captcha_key = ?)
|
||||
AND
|
||||
difficulty_factor = ?
|
||||
);",
|
||||
&captcha_key,
|
||||
difficulty_factor as i32,
|
||||
)
|
||||
.fetch_one(&self.pool).await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
||||
Ok(res.nonce as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO\n mcaptcha_track_nonce (level_id, nonce)\n VALUES ((\n SELECT\n level_id\n FROM\n mcaptcha_levels\n WHERE\n config_id = (SELECT config_id FROM mcaptcha_config WHERE key = ($1))\n AND\n difficulty_factor = $2\n AND\n visitor_threshold = $3\n ), $4);",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Int4",
|
||||
"Int4",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "133ee23ab5ac7c664a86b6edfaa8da79281b6d1f5ba33c642a6ea1b0682fe0b0"
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT nonce FROM mcaptcha_track_nonce\n WHERE level_id = (\n SELECT\n level_id\n FROM\n mcaptcha_levels\n WHERE\n config_id = (SELECT config_id FROM mcaptcha_config WHERE key = ($1))\n AND\n difficulty_factor = $2\n );",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "nonce",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "96f1f1e45144d5add6c4ba4cd2df8eda6043bc8cd6952787f92a687fef778a6e"
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE mcaptcha_track_nonce SET nonce = $3\n WHERE level_id = (\n SELECT\n level_id\n FROM\n mcaptcha_levels\n WHERE\n config_id = (SELECT config_id FROM mcaptcha_config WHERE key = ($1))\n AND\n difficulty_factor = $2\n )\n AND nonce <= $3;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Int4",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e33ee14cf76cd09d9a157b8784a3fe25b89eaca105aa30e479d31b756cd5c88b"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
-- Add migration script here
|
||||
CREATE TABLE IF NOT EXISTS mcaptcha_track_nonce (
|
||||
nonce INTEGER NOT NULL DEFAULT 0,
|
||||
level_id INTEGER references mcaptcha_levels(level_id) ON DELETE CASCADE,
|
||||
ID SERIAL PRIMARY KEY NOT NULL
|
||||
);
|
|
@ -445,6 +445,38 @@ impl MCDatabase for Database {
|
|||
futs.push(fut);
|
||||
}
|
||||
|
||||
try_join_all(futs)
|
||||
.await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
||||
let mut futs = Vec::with_capacity(levels.len());
|
||||
for level in levels.iter() {
|
||||
let difficulty_factor = level.difficulty_factor as i32;
|
||||
let visitor_threshold = level.visitor_threshold as i32;
|
||||
let fut = sqlx::query!(
|
||||
"INSERT INTO
|
||||
mcaptcha_track_nonce (level_id, nonce)
|
||||
VALUES ((
|
||||
SELECT
|
||||
level_id
|
||||
FROM
|
||||
mcaptcha_levels
|
||||
WHERE
|
||||
config_id = (SELECT config_id FROM mcaptcha_config WHERE key = ($1))
|
||||
AND
|
||||
difficulty_factor = $2
|
||||
AND
|
||||
visitor_threshold = $3
|
||||
), $4);",
|
||||
&captcha_key,
|
||||
difficulty_factor,
|
||||
visitor_threshold,
|
||||
0,
|
||||
)
|
||||
.execute(&self.pool);
|
||||
futs.push(fut);
|
||||
}
|
||||
|
||||
try_join_all(futs)
|
||||
.await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
@ -1097,6 +1129,68 @@ impl MCDatabase for Database {
|
|||
|
||||
Ok(res.drain(0..).map(|r| r.psuedo_id).collect())
|
||||
}
|
||||
|
||||
/// Track maximum nonce received against captcha levels
|
||||
async fn update_max_nonce_for_level(
|
||||
&self,
|
||||
captcha_key: &str,
|
||||
difficulty_factor: u32,
|
||||
latest_nonce: u32,
|
||||
) -> DBResult<()> {
|
||||
sqlx::query!(
|
||||
"UPDATE mcaptcha_track_nonce SET nonce = $3
|
||||
WHERE level_id = (
|
||||
SELECT
|
||||
level_id
|
||||
FROM
|
||||
mcaptcha_levels
|
||||
WHERE
|
||||
config_id = (SELECT config_id FROM mcaptcha_config WHERE key = ($1))
|
||||
AND
|
||||
difficulty_factor = $2
|
||||
)
|
||||
AND nonce <= $3;",
|
||||
&captcha_key,
|
||||
difficulty_factor as i32,
|
||||
latest_nonce as i32,
|
||||
)
|
||||
.execute(&self.pool).await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get maximum nonce tracked so far for captcha levels
|
||||
async fn get_max_nonce_for_level(
|
||||
&self,
|
||||
captcha_key: &str,
|
||||
difficulty_factor: u32,
|
||||
) -> DBResult<u32> {
|
||||
struct X {
|
||||
nonce: i32,
|
||||
}
|
||||
|
||||
let res = sqlx::query_as!(
|
||||
X,
|
||||
"SELECT nonce FROM mcaptcha_track_nonce
|
||||
WHERE level_id = (
|
||||
SELECT
|
||||
level_id
|
||||
FROM
|
||||
mcaptcha_levels
|
||||
WHERE
|
||||
config_id = (SELECT config_id FROM mcaptcha_config WHERE key = ($1))
|
||||
AND
|
||||
difficulty_factor = $2
|
||||
);",
|
||||
&captcha_key,
|
||||
difficulty_factor as i32,
|
||||
)
|
||||
.fetch_one(&self.pool).await
|
||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||
|
||||
Ok(res.nonce as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
Loading…
Reference in a new issue