mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-07-10 08:06:42 +02:00
feat: Add ReCaptcha registration flow
This commit is contained in:
parent
13b21b00a9
commit
651d07a609
6 changed files with 80 additions and 13 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -1076,6 +1076,7 @@ dependencies = [
|
|||
"loole",
|
||||
"lru-cache",
|
||||
"rand 0.8.5",
|
||||
"recaptcha-verify",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"ruma",
|
||||
|
@ -3751,6 +3752,17 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "recaptcha-verify"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e3be7b2e46e24637ac96b0c9f70070f188652018573f36f4e511dcad09738a"
|
||||
dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.13"
|
||||
|
|
|
@ -441,6 +441,14 @@
|
|||
#
|
||||
#registration_token_file =
|
||||
|
||||
# This item is undocumented. Please contribute documentation for it.
|
||||
#
|
||||
#recaptcha_site_key =
|
||||
|
||||
# This item is undocumented. Please contribute documentation for it.
|
||||
#
|
||||
#recaptcha_private_site_key =
|
||||
|
||||
# Controls whether encrypted rooms and events are allowed.
|
||||
#
|
||||
#allow_encryption = true
|
||||
|
|
|
@ -291,19 +291,33 @@ pub(crate) async fn register_route(
|
|||
}
|
||||
|
||||
// UIAA
|
||||
let mut uiaainfo;
|
||||
let skip_auth = if services.globals.registration_token.is_some() {
|
||||
let mut uiaainfo = UiaaInfo {
|
||||
flows: Vec::new(),
|
||||
completed: Vec::new(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
let mut skip_auth = false;
|
||||
if services.globals.registration_token.is_some() {
|
||||
// Registration token required
|
||||
uiaainfo = UiaaInfo {
|
||||
flows: vec![AuthFlow {
|
||||
stages: vec![AuthType::RegistrationToken],
|
||||
}],
|
||||
completed: Vec::new(),
|
||||
params: Box::default(),
|
||||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
body.appservice_info.is_some()
|
||||
uiaainfo.flows.push(AuthFlow {
|
||||
stages: vec![AuthType::RegistrationToken],
|
||||
});
|
||||
skip_auth = body.appservice_info.is_some();
|
||||
}
|
||||
if let Some(pubkey) = &services.config.recaptcha_site_key {
|
||||
// ReCaptcha required
|
||||
uiaainfo
|
||||
.flows
|
||||
.push(AuthFlow { stages: vec![AuthType::ReCaptcha] });
|
||||
uiaainfo.params = serde_json::value::to_raw_value(&serde_json::json!({
|
||||
"m.login.recaptcha": {
|
||||
"public_key": pubkey,
|
||||
},
|
||||
}))
|
||||
.expect("Failed to serialize recaptcha params");
|
||||
skip_auth = body.appservice_info.is_some() || skip_auth;
|
||||
} else {
|
||||
// No registration token necessary, but clients must still go through the flow
|
||||
uiaainfo = UiaaInfo {
|
||||
|
@ -313,7 +327,7 @@ pub(crate) async fn register_route(
|
|||
session: None,
|
||||
auth_error: None,
|
||||
};
|
||||
body.appservice_info.is_some() || is_guest
|
||||
skip_auth = skip_auth || body.appservice_info.is_some() || is_guest;
|
||||
};
|
||||
|
||||
if !skip_auth {
|
||||
|
|
|
@ -556,6 +556,10 @@ pub struct Config {
|
|||
/// example: "/etc/continuwuity/.reg_token"
|
||||
pub registration_token_file: Option<PathBuf>,
|
||||
|
||||
pub recaptcha_site_key: Option<String>,
|
||||
|
||||
pub recaptcha_private_site_key: Option<String>,
|
||||
|
||||
/// Controls whether encrypted rooms and events are allowed.
|
||||
#[serde(default = "true_fn")]
|
||||
pub allow_encryption: bool,
|
||||
|
|
|
@ -111,6 +111,7 @@ webpage.workspace = true
|
|||
webpage.optional = true
|
||||
blurhash.workspace = true
|
||||
blurhash.optional = true
|
||||
recaptcha-verify = { version = "0.1.5", default-features = false }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -177,6 +177,34 @@ pub async fn try_auth(
|
|||
// Password was correct! Let's add it to `completed`
|
||||
uiaainfo.completed.push(AuthType::Password);
|
||||
},
|
||||
| AuthData::ReCaptcha(r) => {
|
||||
if self.services.config.recaptcha_private_site_key.is_none() {
|
||||
return Err!(Request(Forbidden("ReCaptcha is not configured.")));
|
||||
}
|
||||
match recaptcha_verify::verify(
|
||||
self.services
|
||||
.config
|
||||
.recaptcha_private_site_key
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
r.response.as_str(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
| Ok(_) => {
|
||||
uiaainfo.completed.push(AuthType::ReCaptcha);
|
||||
},
|
||||
| Err(e) => {
|
||||
error!("ReCaptcha verification failed: {e:?}");
|
||||
uiaainfo.auth_error = Some(ruma::api::client::error::StandardErrorBody {
|
||||
kind: ErrorKind::forbidden(),
|
||||
message: "ReCaptcha verification failed.".to_owned(),
|
||||
});
|
||||
return Ok((false, uiaainfo));
|
||||
},
|
||||
}
|
||||
},
|
||||
| AuthData::RegistrationToken(t) => {
|
||||
let tokens = self.read_tokens().await?;
|
||||
if tokens.contains(t.token.trim()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue