mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2026-02-11 10:05:41 +00:00
Compare commits
9 Commits
update-dep
...
feat-help-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4426057fbc | ||
|
|
1f23999c10 | ||
|
|
0a3d93453e | ||
|
|
939fb5f8b9 | ||
|
|
3a787a6592 | ||
|
|
9dfb0713ad | ||
|
|
ad4582cc16 | ||
|
|
77e4a9c473 | ||
|
|
b6497882d7 |
12
.github/workflows/linux.yml
vendored
12
.github/workflows/linux.yml
vendored
@@ -129,12 +129,12 @@ jobs:
|
|||||||
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
|
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
|
||||||
run: make docker-publish
|
run: make docker-publish
|
||||||
|
|
||||||
# - name: publish bins
|
- name: publish bins
|
||||||
# if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
|
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
|
||||||
# run: ./scripts/publish.sh publish master latest $DUMBSERVE_PASSWORD
|
run: ./scripts/publish.sh publish master latest $DUMBSERVE_PASSWORD
|
||||||
# env:
|
env:
|
||||||
# DUMBSERVE_PASSWORD: ${{ secrets.DUMBSERVE_PASSWORD }}
|
DUMBSERVE_PASSWORD: ${{ secrets.DUMBSERVE_PASSWORD }}
|
||||||
# GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
|
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
|
||||||
|
|
||||||
- name: generate documentation
|
- name: generate documentation
|
||||||
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/mCaptcha')
|
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/mCaptcha')
|
||||||
|
|||||||
@@ -292,6 +292,21 @@ pub trait MCDatabase: std::marker::Send + std::marker::Sync + CloneSPDatabase {
|
|||||||
|
|
||||||
/// Get all psuedo IDs
|
/// Get all psuedo IDs
|
||||||
async fn analytics_get_all_psuedo_ids(&self, page: usize) -> DBResult<Vec<String>>;
|
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)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
|
||||||
|
|||||||
@@ -310,6 +310,33 @@ pub async fn database_works<'a, T: MCDatabase>(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
// analytics end
|
// 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_solve(p.username, c.key).await.unwrap().len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
db.fetch_config_fetched(p.username, c.key)
|
db.fetch_config_fetched(p.username, c.key)
|
||||||
|
|||||||
12
db/db-sqlx-maria/.sqlx/query-216478d53870d7785cd0be43f030883ab79eaafb558d9197d09aea3adbd7b0bc.json
generated
Normal file
12
db/db-sqlx-maria/.sqlx/query-216478d53870d7785cd0be43f030883ab79eaafb558d9197d09aea3adbd7b0bc.json
generated
Normal file
@@ -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"
|
||||||
|
}
|
||||||
12
db/db-sqlx-maria/.sqlx/query-349ba17ff197aca7ee9fbd43e227d181c27ae04702fd6bdb6ddc32aab3bcb1ea.json
generated
Normal file
12
db/db-sqlx-maria/.sqlx/query-349ba17ff197aca7ee9fbd43e227d181c27ae04702fd6bdb6ddc32aab3bcb1ea.json
generated
Normal file
@@ -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"
|
||||||
|
}
|
||||||
12
db/db-sqlx-maria/.sqlx/query-9def82dcec9c8d477824182bb2f71044cc264cf2073ab4f60a0000b435ed0f0b.json
generated
Normal file
12
db/db-sqlx-maria/.sqlx/query-9def82dcec9c8d477824182bb2f71044cc264cf2073ab4f60a0000b435ed0f0b.json
generated
Normal file
@@ -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 ), ?);",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 3
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "9def82dcec9c8d477824182bb2f71044cc264cf2073ab4f60a0000b435ed0f0b"
|
||||||
|
}
|
||||||
25
db/db-sqlx-maria/.sqlx/query-b739ec4cfab1ec60947106c8112e931510c3a50a1606facdde0c0ebb540d5beb.json
generated
Normal file
25
db/db-sqlx-maria/.sqlx/query-b739ec4cfab1ec60947106c8112e931510c3a50a1606facdde0c0ebb540d5beb.json
generated
Normal file
@@ -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);
|
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)
|
try_join_all(futs)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||||
@@ -1087,6 +1120,105 @@ impl MCDatabase for Database {
|
|||||||
|
|
||||||
Ok(res.drain(0..).map(|r| r.psuedo_id).collect())
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn inner_get_max_nonce(
|
||||||
|
pool: &MySqlPool,
|
||||||
|
captcha_key: &str,
|
||||||
|
difficulty_factor: u32,
|
||||||
|
) -> DBResult<X> {
|
||||||
|
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(pool).await
|
||||||
|
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = inner_get_max_nonce(&self.pool, captcha_key, difficulty_factor).await;
|
||||||
|
if let Err(DBError::CaptchaNotFound) = res {
|
||||||
|
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 = ?
|
||||||
|
), ?);",
|
||||||
|
&captcha_key,
|
||||||
|
difficulty_factor as i32,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||||
|
|
||||||
|
let res =
|
||||||
|
inner_get_max_nonce(&self.pool, captcha_key, difficulty_factor).await?;
|
||||||
|
Ok(res.nonce as u32)
|
||||||
|
} else {
|
||||||
|
let res = res?;
|
||||||
|
Ok(res.nonce as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[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": "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 ), $3);",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Text",
|
||||||
|
"Int4",
|
||||||
|
"Int4"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "e0088cf77c1c3a0184f35d1899a6168023fba021adf281cf1c8f9e8ccfe3a03e"
|
||||||
|
}
|
||||||
@@ -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);
|
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)
|
try_join_all(futs)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||||
@@ -1097,6 +1129,104 @@ impl MCDatabase for Database {
|
|||||||
|
|
||||||
Ok(res.drain(0..).map(|r| r.psuedo_id).collect())
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn inner_get_max_nonce(
|
||||||
|
pool: &PgPool,
|
||||||
|
captcha_key: &str,
|
||||||
|
difficulty_factor: u32,
|
||||||
|
) -> DBResult<X> {
|
||||||
|
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(pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = inner_get_max_nonce(&self.pool, captcha_key, difficulty_factor).await;
|
||||||
|
if let Err(DBError::CaptchaNotFound) = res {
|
||||||
|
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
|
||||||
|
), $3);",
|
||||||
|
&captcha_key,
|
||||||
|
difficulty_factor as i32,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| map_row_not_found_err(e, DBError::CaptchaNotFound))?;
|
||||||
|
|
||||||
|
let res =
|
||||||
|
inner_get_max_nonce(&self.pool, captcha_key, difficulty_factor).await?;
|
||||||
|
Ok(res.nonce as u32)
|
||||||
|
} else {
|
||||||
|
let res = res?;
|
||||||
|
Ok(res.nonce as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@@ -37,8 +37,8 @@
|
|||||||
"webpack-dev-server": "^4.15.1"
|
"webpack-dev-server": "^4.15.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mcaptcha/pow-wasm": "^0.1.0-rc1",
|
"@mcaptcha/pow_sha256-polyfill": "^0.1.0-rc2",
|
||||||
"@mcaptcha/pow_sha256-polyfill": "^0.1.0-rc1",
|
"@mcaptcha/vanilla-glue": "^0.1.0-rc1",
|
||||||
"@mcaptcha/vanilla-glue": "^0.1.0-rc1"
|
"@mcaptcha/pow-wasm": "^0.1.0-rc2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ DUMBSERVE_PASSWORD=$4
|
|||||||
DUMBSERVE_HOST="https://$DUMBSERVE_USERNAME:$DUMBSERVE_PASSWORD@dl.mcaptcha.org"
|
DUMBSERVE_HOST="https://$DUMBSERVE_USERNAME:$DUMBSERVE_PASSWORD@dl.mcaptcha.org"
|
||||||
|
|
||||||
NAME=mcaptcha
|
NAME=mcaptcha
|
||||||
KEY=0CBABF3084E84E867A76709750BE39D10ECE01FB
|
KEY=73DAC973A9ADBB9ADCB5CDC4595A08135BA9FF73
|
||||||
|
|
||||||
TMP_DIR=$(mktemp -d)
|
TMP_DIR=$(mktemp -d)
|
||||||
FILENAME="$NAME-$2-linux-amd64"
|
FILENAME="$NAME-$2-linux-amd64"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
//use actix::prelude::*;
|
//use actix::prelude::*;
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
|
use libmcaptcha::pow::PoWConfig;
|
||||||
use libmcaptcha::{
|
use libmcaptcha::{
|
||||||
defense::LevelBuilder, master::messages::AddSiteBuilder, DefenseBuilder,
|
defense::LevelBuilder, master::messages::AddSiteBuilder, DefenseBuilder,
|
||||||
MCaptchaBuilder,
|
MCaptchaBuilder,
|
||||||
@@ -21,7 +22,13 @@ pub struct GetConfigPayload {
|
|||||||
pub key: String,
|
pub key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// API keys are mcaptcha actor names
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ApiPoWConfig {
|
||||||
|
pub string: String,
|
||||||
|
pub difficulty_factor: u32,
|
||||||
|
pub salt: String,
|
||||||
|
pub max_recorded_nonce: u32,
|
||||||
|
}
|
||||||
|
|
||||||
/// get PoW configuration for an mcaptcha key
|
/// get PoW configuration for an mcaptcha key
|
||||||
#[my_codegen::post(path = "V1_API_ROUTES.pow.get_config()")]
|
#[my_codegen::post(path = "V1_API_ROUTES.pow.get_config()")]
|
||||||
@@ -35,52 +42,34 @@ pub async fn get_config(
|
|||||||
}
|
}
|
||||||
let payload = payload.into_inner();
|
let payload = payload.into_inner();
|
||||||
|
|
||||||
match data.captcha.get_pow(payload.key.clone()).await {
|
let config: ServiceResult<PoWConfig> =
|
||||||
Ok(Some(config)) => {
|
match data.captcha.get_pow(payload.key.clone()).await {
|
||||||
data.stats.record_fetch(&data, &payload.key).await?;
|
Ok(Some(config)) => Ok(config),
|
||||||
Ok(HttpResponse::Ok().json(config))
|
Ok(None) => {
|
||||||
}
|
init_mcaptcha(&data, &payload.key).await?;
|
||||||
Ok(None) => {
|
let config = data
|
||||||
init_mcaptcha(&data, &payload.key).await?;
|
.captcha
|
||||||
let config = data
|
.get_pow(payload.key.clone())
|
||||||
.captcha
|
.await
|
||||||
.get_pow(payload.key.clone())
|
.expect("mcaptcha should be initialized and ready to go");
|
||||||
.await
|
Ok(config.unwrap())
|
||||||
.expect("mcaptcha should be initialized and ready to go");
|
}
|
||||||
// background it. would require data::Data to be static
|
Err(e) => Err(e.into()),
|
||||||
// to satidfy lifetime
|
};
|
||||||
data.stats.record_fetch(&data, &payload.key).await?;
|
let config = config?;
|
||||||
Ok(HttpResponse::Ok().json(config))
|
let max_nonce = data
|
||||||
}
|
.db
|
||||||
Err(e) => Err(e.into()),
|
.get_max_nonce_for_level(&payload.key, config.difficulty_factor)
|
||||||
}
|
.await?;
|
||||||
|
data.stats.record_fetch(&data, &payload.key).await?;
|
||||||
|
|
||||||
// match res.exists {
|
let config = ApiPoWConfig {
|
||||||
// Some(true) => {
|
string: config.string,
|
||||||
// match data.captcha.get_pow(payload.key.clone()).await {
|
difficulty_factor: config.difficulty_factor,
|
||||||
// Ok(Some(config)) => {
|
salt: config.salt,
|
||||||
// record_fetch(&payload.key, &data.db).await;
|
max_recorded_nonce: max_nonce,
|
||||||
// Ok(HttpResponse::Ok().json(config))
|
};
|
||||||
// }
|
Ok(HttpResponse::Ok().json(config))
|
||||||
// Ok(None) => {
|
|
||||||
// init_mcaptcha(&data, &payload.key).await?;
|
|
||||||
// let config = data
|
|
||||||
// .captcha
|
|
||||||
// .get_pow(payload.key.clone())
|
|
||||||
// .await
|
|
||||||
// .expect("mcaptcha should be initialized and ready to go");
|
|
||||||
// // background it. would require data::Data to be static
|
|
||||||
// // to satidfy lifetime
|
|
||||||
// record_fetch(&payload.key, &data.db).await;
|
|
||||||
// Ok(HttpResponse::Ok().json(config))
|
|
||||||
// }
|
|
||||||
// Err(e) => Err(e.into()),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Some(false) => Err(ServiceError::TokenNotFound),
|
|
||||||
// None => Err(ServiceError::TokenNotFound),
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
/// Call this when [MCaptcha][libmcaptcha::MCaptcha] is not in master.
|
/// Call this when [MCaptcha][libmcaptcha::MCaptcha] is not in master.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ pub async fn verify_pow(
|
|||||||
let payload = payload.into_inner();
|
let payload = payload.into_inner();
|
||||||
let worker_type = payload.worker_type.clone();
|
let worker_type = payload.worker_type.clone();
|
||||||
let time = payload.time;
|
let time = payload.time;
|
||||||
|
let nonce = payload.nonce;
|
||||||
let (res, difficulty_factor) = data.captcha.verify_pow(payload.into(), ip).await?;
|
let (res, difficulty_factor) = data.captcha.verify_pow(payload.into(), ip).await?;
|
||||||
data.stats.record_solve(&data, &key).await?;
|
data.stats.record_solve(&data, &key).await?;
|
||||||
if let (Some(time), Some(worker_type)) = (time, worker_type) {
|
if let (Some(time), Some(worker_type)) = (time, worker_type) {
|
||||||
@@ -75,6 +76,9 @@ pub async fn verify_pow(
|
|||||||
};
|
};
|
||||||
data.db.analysis_save(&key, &analytics).await?;
|
data.db.analysis_save(&key, &analytics).await?;
|
||||||
}
|
}
|
||||||
|
data.db
|
||||||
|
.update_max_nonce_for_level(&key, difficulty_factor, nonce as u32)
|
||||||
|
.await?;
|
||||||
let payload = ValidationToken { token: res };
|
let payload = ValidationToken { token: res };
|
||||||
Ok(HttpResponse::Ok().json(payload))
|
Ok(HttpResponse::Ok().json(payload))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
|||||||
<. } .>
|
<. } .>
|
||||||
|
|
||||||
<label class="sitekey-form__label" for="publish_benchmarks">
|
<label class="sitekey-form__label" for="publish_benchmarks">
|
||||||
Anonymously publish CAPTCHA performance statistics to help other webmasters
|
Anonymously publish CAPTCHA performance statistics to help other webmasters. <a href="https://mcaptcha.org/blog/introducing-mcaptcha-net">Please see here for more info</a>.
|
||||||
<input
|
<input
|
||||||
class="sitekey-form__input"
|
class="sitekey-form__input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
|||||||
|
|
||||||
|
|
||||||
<label class="sitekey-form__label" for="publish_benchmarks">
|
<label class="sitekey-form__label" for="publish_benchmarks">
|
||||||
Anonymously publish CAPTCHA performance statistics to help other webmasters
|
Anonymously publish CAPTCHA performance statistics to help other webmasters. <a href="https://mcaptcha.org/blog/introducing-mcaptcha-net">Please see here for more info</a>.
|
||||||
<input
|
<input
|
||||||
class="sitekey-form__input"
|
class="sitekey-form__input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@@ -6,51 +6,54 @@ SPDX-License-Identifier: MIT OR Apache-2.0
|
|||||||
|
|
||||||
<. include!("../components/headers/widget-headers.html"); .>
|
<. include!("../components/headers/widget-headers.html"); .>
|
||||||
<body>
|
<body>
|
||||||
<form class="widget__contaienr">
|
<main class="widget__container">
|
||||||
<noscript>
|
<form class="widget__inner-container">
|
||||||
<div class="widget__noscript-container">
|
<noscript>
|
||||||
<span class="widget__noscript-warning">
|
<div class="widget__noscript-container">
|
||||||
Please enable JavaScript to receive mCaptcha challenge
|
<span class="widget__noscript-warning">
|
||||||
</span>
|
Please enable JavaScript to receive mCaptcha challenge
|
||||||
<a class="widget__source-code" href="https://github.com/mCaptcha">
|
</span>
|
||||||
Read our source code
|
<a class="widget__source-code" href="https://github.com/mCaptcha">
|
||||||
</a>
|
Read our source code
|
||||||
</div>
|
</a>
|
||||||
</noscript>
|
</div>
|
||||||
<label class="widget__verification-container" for="widget__verification-checkbox">
|
</noscript>
|
||||||
<input
|
<label class="widget__verification-container" for="widget__verification-checkbox">
|
||||||
id="widget__verification-checkbox"
|
<input
|
||||||
class="widget__verification-checkbox"
|
id="widget__verification-checkbox"
|
||||||
type="checkbox" />
|
class="widget__verification-checkbox"
|
||||||
<span id="widget__verification-text--before">I'm not a robot</span>
|
type="checkbox" />
|
||||||
<span id="widget__verification-text--during">Processing...</span>
|
<span id="widget__verification-text--before">I'm not a robot</span>
|
||||||
<span id="widget__verification-text--after">Verified!</span>
|
<span id="widget__verification-text--during">Processing...</span>
|
||||||
<span id="widget__verification-text--error">Something went wrong</span>
|
<span id="widget__verification-text--after">Verified!</span>
|
||||||
</label>
|
<span id="widget__verification-text--error">Something went wrong</span>
|
||||||
<div class="widget__mcaptcha-details">
|
</label>
|
||||||
<a href="<.= crate::PKG_HOMEPAGE .>"
|
<div class="widget__mcaptcha-details">
|
||||||
class="widget__mcaptcha-logo-container"
|
<a href="<.= crate::PKG_HOMEPAGE .>"
|
||||||
target="_blank"
|
class="widget__mcaptcha-logo-container"
|
||||||
>
|
target="_blank"
|
||||||
<img
|
>
|
||||||
class="widget__mcaptcha-logo"
|
<img
|
||||||
src="<.= crate::FILES.get("./static/cache/img/icon-trans.png").unwrap().>"
|
class="widget__mcaptcha-logo"
|
||||||
alt="mCaptcha logo"
|
src="<.= crate::FILES.get("./static/cache/img/icon-trans.png").unwrap().>"
|
||||||
/>
|
alt="mCaptcha logo"
|
||||||
<p class="widget__mcaptcha-brand-name">mCaptcha</p>
|
/>
|
||||||
</a>
|
<p class="widget__mcaptcha-brand-name">mCaptcha</p>
|
||||||
<div class="widget__mcaptcha-info-container">
|
|
||||||
<a class="widget__mcaptcha-info-link"
|
|
||||||
target="_blank"
|
|
||||||
href="<.= crate::PKG_HOMEPAGE .><.= crate::PAGES.privacy .>">
|
|
||||||
Privacy
|
|
||||||
</a>
|
|
||||||
<a class="widget__mcaptcha-info-link"
|
|
||||||
target="_blank"
|
|
||||||
href="<.= crate::PKG_HOMEPAGE .><.= crate::PAGES.security .>">
|
|
||||||
Terms
|
|
||||||
</a>
|
</a>
|
||||||
|
<div class="widget__mcaptcha-info-container">
|
||||||
|
<a class="widget__mcaptcha-info-link"
|
||||||
|
target="_blank"
|
||||||
|
href="<.= crate::PKG_HOMEPAGE .><.= crate::PAGES.privacy .>">
|
||||||
|
Privacy
|
||||||
|
</a>
|
||||||
|
<a class="widget__mcaptcha-info-link"
|
||||||
|
target="_blank"
|
||||||
|
href="<.= crate::PKG_HOMEPAGE .><.= crate::PAGES.security .>">
|
||||||
|
Terms
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
<div class="progress__bar"><div class="progress__fill"></div></div>
|
||||||
|
</main>
|
||||||
<.include!("./footer.html"); .>
|
<.include!("./footer.html"); .>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
import { Work, ServiceWorkerWork } from "./types";
|
import { Work, ServiceWorkerMessage } from "./types";
|
||||||
import fetchPoWConfig from "./fetchPoWConfig";
|
import fetchPoWConfig from "./fetchPoWConfig";
|
||||||
import sendWork from "./sendWork";
|
import sendWork from "./sendWork";
|
||||||
import sendToParent from "./sendToParent";
|
import sendToParent from "./sendToParent";
|
||||||
@@ -24,6 +24,9 @@ export const registerVerificationEventHandler = (): void => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const solveCaptchaRunner = async (e: Event): Promise<void> => {
|
export const solveCaptchaRunner = async (e: Event): Promise<void> => {
|
||||||
|
const PROGRESS_FILL = <HTMLElement>document.querySelector(".progress__fill");
|
||||||
|
let width = 0;
|
||||||
|
|
||||||
if (LOCK) {
|
if (LOCK) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
@@ -32,6 +35,8 @@ export const solveCaptchaRunner = async (e: Event): Promise<void> => {
|
|||||||
try {
|
try {
|
||||||
LOCK = true;
|
LOCK = true;
|
||||||
if (CONST.btn().checked == false) {
|
if (CONST.btn().checked == false) {
|
||||||
|
width = 0;
|
||||||
|
PROGRESS_FILL.style.width = `${width}%`;
|
||||||
CONST.messageText().before();
|
CONST.messageText().before();
|
||||||
LOCK = false;
|
LOCK = false;
|
||||||
return;
|
return;
|
||||||
@@ -43,32 +48,49 @@ export const solveCaptchaRunner = async (e: Event): Promise<void> => {
|
|||||||
CONST.messageText().during();
|
CONST.messageText().during();
|
||||||
// 1. get config
|
// 1. get config
|
||||||
const config = await fetchPoWConfig();
|
const config = await fetchPoWConfig();
|
||||||
|
const max_recorded_nonce = config.max_recorded_nonce;
|
||||||
// 2. prove work
|
// 2. prove work
|
||||||
worker.postMessage(config);
|
worker.postMessage(config);
|
||||||
|
|
||||||
worker.onmessage = async (event: MessageEvent) => {
|
worker.onmessage = async (event: MessageEvent) => {
|
||||||
const resp: ServiceWorkerWork = event.data;
|
const resp: ServiceWorkerMessage = event.data;
|
||||||
console.log(
|
|
||||||
`Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.work.time}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const proof: Work = {
|
if (resp.type === "work") {
|
||||||
key: CONST.sitekey(),
|
width = 80;
|
||||||
string: config.string,
|
PROGRESS_FILL.style.width = `${width}%`;
|
||||||
nonce: resp.work.nonce,
|
console.log(
|
||||||
result: resp.work.result,
|
`Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.value.work.time}`
|
||||||
time: Math.trunc(resp.work.time),
|
);
|
||||||
worker_type: resp.work.worker_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. submit work
|
const proof: Work = {
|
||||||
const token = await sendWork(proof);
|
key: CONST.sitekey(),
|
||||||
// 4. send token
|
string: config.string,
|
||||||
sendToParent(token);
|
nonce: resp.value.work.nonce,
|
||||||
// 5. mark checkbox checked
|
result: resp.value.work.result,
|
||||||
CONST.btn().checked = true;
|
time: Math.trunc(resp.value.work.time),
|
||||||
CONST.messageText().after();
|
worker_type: resp.value.work.worker_type,
|
||||||
LOCK = false;
|
};
|
||||||
|
|
||||||
|
width = 90;
|
||||||
|
PROGRESS_FILL.style.width = `${width}%`;
|
||||||
|
// 3. submit work
|
||||||
|
const token = await sendWork(proof);
|
||||||
|
// 4. send token
|
||||||
|
sendToParent(token);
|
||||||
|
// 5. mark checkbox checked
|
||||||
|
CONST.btn().checked = true;
|
||||||
|
width = 100;
|
||||||
|
PROGRESS_FILL.style.width = `${width}%`;
|
||||||
|
CONST.messageText().after();
|
||||||
|
LOCK = false;
|
||||||
|
}
|
||||||
|
if (resp.type === "progress") {
|
||||||
|
if (width < 80) {
|
||||||
|
width = (resp.nonce / max_recorded_nonce) * 100;
|
||||||
|
PROGRESS_FILL.style.width = `${width}%`;
|
||||||
|
}
|
||||||
|
console.log(`received nonce ${resp.nonce}`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
CONST.messageText().error();
|
CONST.messageText().error();
|
||||||
|
|||||||
@@ -7,106 +7,138 @@
|
|||||||
|
|
||||||
@import "../reset";
|
@import "../reset";
|
||||||
|
|
||||||
.widget__contaienr {
|
body {
|
||||||
align-items: center;
|
display: flex;
|
||||||
box-sizing: border-box;
|
flex-direction: column;
|
||||||
display: flex;
|
width: 100%;
|
||||||
height: 100%;
|
}
|
||||||
|
|
||||||
|
.widget__container {
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
margin: auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget__inner-container {
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__noscript-container {
|
.widget__noscript-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__noscript-warning {
|
.widget__noscript-warning {
|
||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
flex: 2;
|
flex: 2;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__source-code {
|
.widget__source-code {
|
||||||
display: block;
|
display: block;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__verification-container {
|
.widget__verification-container {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: none;
|
display: none;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__verification-checkbox {
|
.widget__verification-checkbox {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#widget__verification-text--during {
|
#widget__verification-text--during {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#widget__verification-text--after {
|
#widget__verification-text--after {
|
||||||
display: none;
|
display: none;
|
||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
#widget__verification-text--error {
|
#widget__verification-text--error {
|
||||||
display: none;
|
display: none;
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__verification-checkbox:checked ~ #widget__verification-text--before {
|
.widget__verification-checkbox:checked ~ #widget__verification-text--before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__verification-checkbox:checked ~ #widget__verification-text--during {
|
.widget__verification-checkbox:checked ~ #widget__verification-text--during {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__verification-checkbox:checked ~ #widget__verification-text--error {
|
.widget__verification-checkbox:checked ~ #widget__verification-text--error {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__verification-checkbox:checked ~ #widget__verification-text--after {
|
.widget__verification-checkbox:checked ~ #widget__verification-text--after {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__mcaptcha-details {
|
.widget__mcaptcha-details {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__mcaptcha-brand-name {
|
.widget__mcaptcha-brand-name {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__mcaptcha-logo {
|
.widget__mcaptcha-logo {
|
||||||
display: block;
|
display: block;
|
||||||
width: 35px;
|
width: 35px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__mcaptcha-info-container {
|
.widget__mcaptcha-info-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget__mcaptcha-info-link {
|
.widget__mcaptcha-info-link {
|
||||||
font-size: 0.5rem;
|
font-size: 0.5rem;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* progress bar courtesy of https://codepen.io/Bizzy-Coding/pen/poOymVJ?editors=1111 */
|
||||||
|
.progress__bar {
|
||||||
|
position: relative;
|
||||||
|
height: 5px;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress__fill {
|
||||||
|
background: #65a2e0;
|
||||||
|
border-radius: 15px;
|
||||||
|
height: 100%;
|
||||||
|
width: 0%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
import { gen_pow } from "@mcaptcha/pow-wasm";
|
import { stepped_gen_pow } from "@mcaptcha/pow-wasm";
|
||||||
import * as p from "@mcaptcha/pow_sha256-polyfill";
|
import * as p from "@mcaptcha/pow_sha256-polyfill";
|
||||||
import { WasmWork, PoWConfig, SubmitWork } from "./types";
|
import { WasmWork, PoWConfig, SubmitWork } from "./types";
|
||||||
|
|
||||||
@@ -12,19 +12,25 @@ import { WasmWork, PoWConfig, SubmitWork } from "./types";
|
|||||||
* @param {PoWConfig} config - the proof-of-work configuration using which
|
* @param {PoWConfig} config - the proof-of-work configuration using which
|
||||||
* work needs to be computed
|
* work needs to be computed
|
||||||
* */
|
* */
|
||||||
const prove = async (config: PoWConfig): Promise<SubmitWork> => {
|
const prove = async (
|
||||||
|
config: PoWConfig,
|
||||||
|
progress: (nonce: number) => void
|
||||||
|
): Promise<SubmitWork> => {
|
||||||
const WASM = "wasm";
|
const WASM = "wasm";
|
||||||
const JS = "js";
|
const JS = "js";
|
||||||
|
const STEPS = 5000;
|
||||||
if (WasmSupported) {
|
if (WasmSupported) {
|
||||||
let proof: WasmWork = null;
|
let proof: WasmWork = null;
|
||||||
let res: SubmitWork = null;
|
let res: SubmitWork = null;
|
||||||
let time: number = null;
|
let time: number = null;
|
||||||
|
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
const proofString = gen_pow(
|
const proofString = stepped_gen_pow(
|
||||||
config.salt,
|
config.salt,
|
||||||
config.string,
|
config.string,
|
||||||
config.difficulty_factor
|
config.difficulty_factor,
|
||||||
|
STEPS,
|
||||||
|
progress
|
||||||
);
|
);
|
||||||
const t1 = performance.now();
|
const t1 = performance.now();
|
||||||
time = t1 - t0;
|
time = t1 - t0;
|
||||||
@@ -47,10 +53,12 @@ const prove = async (config: PoWConfig): Promise<SubmitWork> => {
|
|||||||
|
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
|
|
||||||
proof = await p.generate_work(
|
proof = await p.stepped_generate_work(
|
||||||
config.salt,
|
config.salt,
|
||||||
config.string,
|
config.string,
|
||||||
config.difficulty_factor
|
config.difficulty_factor,
|
||||||
|
STEPS,
|
||||||
|
progress
|
||||||
);
|
);
|
||||||
const t1 = performance.now();
|
const t1 = performance.now();
|
||||||
time = t1 - t0;
|
time = t1 - t0;
|
||||||
|
|||||||
@@ -6,17 +6,31 @@
|
|||||||
import log from "../logger";
|
import log from "../logger";
|
||||||
|
|
||||||
import prove from "./prove";
|
import prove from "./prove";
|
||||||
import { PoWConfig, ServiceWorkerWork } from "./types";
|
import { PoWConfig, ServiceWorkerMessage, ServiceWorkerWork } from "./types";
|
||||||
|
|
||||||
log.log("worker registered");
|
log.log("worker registered");
|
||||||
onmessage = async (e) => {
|
onmessage = async (e) => {
|
||||||
console.debug("message received at worker");
|
console.debug("message received at worker");
|
||||||
const config: PoWConfig = e.data;
|
const config: PoWConfig = e.data;
|
||||||
|
|
||||||
const work = await prove(config);
|
const progressCallback = (nonce: number) => {
|
||||||
const res: ServiceWorkerWork = {
|
const res: ServiceWorkerMessage = {
|
||||||
|
type: "progress",
|
||||||
|
nonce: nonce,
|
||||||
|
};
|
||||||
|
|
||||||
|
postMessage(res);
|
||||||
|
};
|
||||||
|
|
||||||
|
const work = await prove(config, progressCallback);
|
||||||
|
const w: ServiceWorkerWork = {
|
||||||
work,
|
work,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const res: ServiceWorkerMessage = {
|
||||||
|
type: "work",
|
||||||
|
value: w,
|
||||||
|
};
|
||||||
|
|
||||||
postMessage(res);
|
postMessage(res);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,8 +32,13 @@ export type PoWConfig = {
|
|||||||
string: string;
|
string: string;
|
||||||
difficulty_factor: number;
|
difficulty_factor: number;
|
||||||
salt: string;
|
salt: string;
|
||||||
|
max_recorded_nonce: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Token = {
|
export type Token = {
|
||||||
token: string;
|
token: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ServiceWorkerMessage =
|
||||||
|
| { type: "work"; value: ServiceWorkerWork }
|
||||||
|
| { type: "progress"; nonce: number };
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@@ -631,15 +631,15 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@mcaptcha/core-glue/-/core-glue-0.1.0-rc1.tgz#76d665a3fc537062061e12e274f969ac3e053685"
|
resolved "https://registry.yarnpkg.com/@mcaptcha/core-glue/-/core-glue-0.1.0-rc1.tgz#76d665a3fc537062061e12e274f969ac3e053685"
|
||||||
integrity sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg==
|
integrity sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg==
|
||||||
|
|
||||||
"@mcaptcha/pow-wasm@^0.1.0-rc1":
|
"@mcaptcha/pow-wasm@^0.1.0-rc2":
|
||||||
version "0.1.0-rc1"
|
version "0.1.0-rc2"
|
||||||
resolved "https://registry.yarnpkg.com/@mcaptcha/pow-wasm/-/pow-wasm-0.1.0-rc1.tgz#eef8409e0c74e9c7261587bdebd80a8c4af92f9e"
|
resolved "https://registry.yarnpkg.com/@mcaptcha/pow-wasm/-/pow-wasm-0.1.0-rc2.tgz#c7aaa678325600a178b11a702e2aeb9f8143e605"
|
||||||
integrity sha512-7+PGKoe1StFRsa9TEqztzK4/obbdY4OfavFX+geTk8b3K26D+eHPyimJ9BPlpI1VZl8ujR3CnbfbnQSRaqS7ZQ==
|
integrity sha512-2G0nQ2GQWECRcE5kzfULDsQ032s6/PDzE1rncMdQAR1Mu2YQfFZHgnX4zLJmQnjKIhy9meIjXvatVSyIllrbtg==
|
||||||
|
|
||||||
"@mcaptcha/pow_sha256-polyfill@^0.1.0-rc1":
|
"@mcaptcha/pow_sha256-polyfill@^0.1.0-rc2":
|
||||||
version "0.1.0-rc1"
|
version "0.1.0-rc2"
|
||||||
resolved "https://registry.yarnpkg.com/@mcaptcha/pow_sha256-polyfill/-/pow_sha256-polyfill-0.1.0-rc1.tgz#dfeee88f5f6fd99aeae65dbcff6fbb09fe8a1696"
|
resolved "https://registry.yarnpkg.com/@mcaptcha/pow_sha256-polyfill/-/pow_sha256-polyfill-0.1.0-rc2.tgz#253320e7a6666e395ef9dfb123d1102066d72b87"
|
||||||
integrity sha512-OFA4W3/vh8ORUnifbm8c/8eP22CbiXr4Un6/l4fMyqLj1aoQLMGAiuqab0trGqBnY0DU2bwTMyxflx26/cWgIw==
|
integrity sha512-ERIbxIo+ZnQKtti/T4FLmcY0neuc5R05L97qYc62Hm++i+3dx/W6A8oC4V9U0XKCPYnHZFoZozAZlbsGXjrsVQ==
|
||||||
|
|
||||||
"@mcaptcha/vanilla-glue@^0.1.0-rc1":
|
"@mcaptcha/vanilla-glue@^0.1.0-rc1":
|
||||||
version "0.1.0-rc1"
|
version "0.1.0-rc1"
|
||||||
|
|||||||
Reference in New Issue
Block a user