mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
feat: Add a webpage for threepid validation links
This commit is contained in:
@@ -122,7 +122,7 @@ impl Service {
|
|||||||
/// if they were not.
|
/// if they were not.
|
||||||
pub async fn empower_first_user(&self, user: &UserId) -> Result<bool> {
|
pub async fn empower_first_user(&self, user: &UserId) -> Result<bool> {
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "welcome.md.j2")]
|
#[template(path = "welcome.md")]
|
||||||
struct WelcomeMessage<'a> {
|
struct WelcomeMessage<'a> {
|
||||||
config: &'a Dep<config::Service>,
|
config: &'a Dep<config::Service>,
|
||||||
domain: &'a str,
|
domain: &'a str,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub trait MessageTemplate: Template {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "mail/change_email.txt.j2")]
|
#[template(path = "mail/change_email.txt")]
|
||||||
pub struct ChangeEmail<'a> {
|
pub struct ChangeEmail<'a> {
|
||||||
pub user_id: &'a UserId,
|
pub user_id: &'a UserId,
|
||||||
pub verification_link: String,
|
pub verification_link: String,
|
||||||
@@ -17,7 +17,7 @@ impl MessageTemplate for ChangeEmail<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "mail/new_account.txt.j2")]
|
#[template(path = "mail/new_account.txt")]
|
||||||
pub struct NewAccount<'a> {
|
pub struct NewAccount<'a> {
|
||||||
pub server_name: &'a str,
|
pub server_name: &'a str,
|
||||||
pub verification_link: String,
|
pub verification_link: String,
|
||||||
@@ -28,7 +28,7 @@ impl MessageTemplate for NewAccount<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "mail/password_reset.txt.j2")]
|
#[template(path = "mail/password_reset.txt")]
|
||||||
pub struct PasswordReset<'a> {
|
pub struct PasswordReset<'a> {
|
||||||
pub display_name: Option<&'a str>,
|
pub display_name: Option<&'a str>,
|
||||||
pub user_id: &'a UserId,
|
pub user_id: &'a UserId,
|
||||||
@@ -40,7 +40,7 @@ impl MessageTemplate for PasswordReset<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "mail/test.txt.j2")]
|
#[template(path = "mail/test.txt")]
|
||||||
pub struct Test;
|
pub struct Test;
|
||||||
|
|
||||||
impl MessageTemplate for Test {
|
impl MessageTemplate for Test {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
{% extends "_base.txt.j2" %}
|
{% extends "_base.txt" %}
|
||||||
|
|
||||||
{% block content -%}
|
{% block content -%}
|
||||||
Hello!
|
Hello!
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
{% extends "_base.txt.j2" %}
|
{% extends "_base.txt" %}
|
||||||
|
|
||||||
{% block content -%}
|
{% block content -%}
|
||||||
Hello!
|
Hello!
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
{% extends "_base.txt.j2" %}
|
{% extends "_base.txt" %}
|
||||||
|
|
||||||
{% block content -%}
|
{% block content -%}
|
||||||
{%- if let Some(display_name) = display_name -%}
|
{%- if let Some(display_name) = display_name -%}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{% extends "_base.txt.j2" %}
|
{% extends "_base.txt" %}
|
||||||
|
|
||||||
{% block content -%}
|
{% block content -%}
|
||||||
If you're seeing this, SMTP is configured correctly. :3
|
If you're seeing this, SMTP is configured correctly. :3
|
||||||
@@ -90,6 +90,7 @@ pub fn build() -> Router<state::State> {
|
|||||||
.merge(resources::build())
|
.merge(resources::build())
|
||||||
.merge(password_reset::build())
|
.merge(password_reset::build())
|
||||||
.merge(debug::build())
|
.merge(debug::build())
|
||||||
|
.merge(threepid::build())
|
||||||
.fallback(async || WebError::NotFound),
|
.fallback(async || WebError::NotFound),
|
||||||
)
|
)
|
||||||
.layer(CatchPanicLayer::custom(|panic: Box<dyn Any + Send + 'static>| {
|
.layer(CatchPanicLayer::custom(|panic: Box<dyn Any + Send + 'static>| {
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
use askama::Template;
|
|
||||||
use axum::{Router, extract::State, response::IntoResponse, routing::get};
|
use axum::{Router, extract::State, response::IntoResponse, routing::get};
|
||||||
|
|
||||||
use crate::{WebError, template};
|
use crate::{WebError, template};
|
||||||
|
|
||||||
pub(crate) fn build() -> Router<crate::State> {
|
pub(crate) fn build() -> Router<crate::State> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(index_handler))
|
.route("/", get(index))
|
||||||
.route("/_continuwuity/", get(index_handler))
|
.route("/_continuwuity/", get(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn index_handler(
|
async fn index(State(services): State<crate::State>) -> Result<impl IntoResponse, WebError> {
|
||||||
State(services): State<crate::State>,
|
|
||||||
) -> Result<impl IntoResponse, WebError> {
|
|
||||||
template! {
|
template! {
|
||||||
struct Index<'a> use "index.html.j2" {
|
struct Index<'a> use "index.html.j2" {
|
||||||
server_name: &'a str,
|
server_name: &'a str,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pub(super) mod debug;
|
|||||||
pub(super) mod index;
|
pub(super) mod index;
|
||||||
pub(super) mod password_reset;
|
pub(super) mod password_reset;
|
||||||
pub(super) mod resources;
|
pub(super) mod resources;
|
||||||
|
pub(super) mod threepid;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct TemplateContext {
|
pub(crate) struct TemplateContext {
|
||||||
@@ -43,6 +44,8 @@ macro_rules! template {
|
|||||||
#[allow(single_use_lifetimes)]
|
#[allow(single_use_lifetimes)]
|
||||||
impl$(<$lifetime>)? axum::response::IntoResponse for $name$(<$lifetime>)? {
|
impl$(<$lifetime>)? axum::response::IntoResponse for $name$(<$lifetime>)? {
|
||||||
fn into_response(self) -> axum::response::Response {
|
fn into_response(self) -> axum::response::Response {
|
||||||
|
use askama::Template;
|
||||||
|
|
||||||
match self.render() {
|
match self.render() {
|
||||||
Ok(rendered) => axum::response::Html(rendered).into_response(),
|
Ok(rendered) => axum::response::Html(rendered).into_response(),
|
||||||
Err(err) => $crate::WebError::from(err).into_response()
|
Err(err) => $crate::WebError::from(err).into_response()
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use askama::Template;
|
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
extract::{
|
extract::{
|
||||||
@@ -20,11 +19,6 @@ use crate::{
|
|||||||
|
|
||||||
const INVALID_TOKEN_ERROR: &str = "Invalid reset token. Your reset link may have expired.";
|
const INVALID_TOKEN_ERROR: &str = "Invalid reset token. Your reset link may have expired.";
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct PasswordResetQuery {
|
|
||||||
token: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
template! {
|
template! {
|
||||||
struct PasswordReset<'a> use "password_reset.html.j2" {
|
struct PasswordReset<'a> use "password_reset.html.j2" {
|
||||||
user_card: UserCard<'a>,
|
user_card: UserCard<'a>,
|
||||||
@@ -63,6 +57,11 @@ pub(crate) fn build() -> Router<crate::State> {
|
|||||||
.route("/account/reset_password", get(get_password_reset).post(post_password_reset))
|
.route("/account/reset_password", get(get_password_reset).post(post_password_reset))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct PasswordResetQuery {
|
||||||
|
token: String,
|
||||||
|
}
|
||||||
|
|
||||||
async fn password_reset_form(
|
async fn password_reset_form(
|
||||||
services: crate::State,
|
services: crate::State,
|
||||||
query: PasswordResetQuery,
|
query: PasswordResetQuery,
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends "_layout.html.j2" %}
|
||||||
|
|
||||||
|
{%- block content -%}
|
||||||
|
<div class="panel">
|
||||||
|
<h1>Email verification</h1>
|
||||||
|
<p>Your email address has been verified. Return to your Matrix client to continue.</p>
|
||||||
|
</div>
|
||||||
|
{%- endblock content -%}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
use axum::{
|
||||||
|
Router,
|
||||||
|
extract::{Query, State, rejection::QueryRejection},
|
||||||
|
response::IntoResponse,
|
||||||
|
routing::get,
|
||||||
|
};
|
||||||
|
use ruma::OwnedSessionId;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::{WebError, template};
|
||||||
|
|
||||||
|
template! {
|
||||||
|
struct ThreepidValidation use "threepid_validation.html.j2" {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build() -> Router<crate::State> {
|
||||||
|
Router::new().route("/3pid/email/validate", get(threepid_validation))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ThreepidValidationQuery {
|
||||||
|
session: OwnedSessionId,
|
||||||
|
token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn threepid_validation(
|
||||||
|
State(services): State<crate::State>,
|
||||||
|
query: Result<Query<ThreepidValidationQuery>, QueryRejection>,
|
||||||
|
) -> Result<impl IntoResponse, WebError> {
|
||||||
|
let Query(query) = query?;
|
||||||
|
|
||||||
|
services
|
||||||
|
.threepid
|
||||||
|
.try_validate_session(&query.session, &query.token)
|
||||||
|
.await
|
||||||
|
.map_err(|message| WebError::BadRequest(message.into_owned()))?;
|
||||||
|
|
||||||
|
Ok(ThreepidValidation::new(&services))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user