Compare commits

...
Sign in to create a new pull request.

6 commits

Author SHA1 Message Date
Jade Ellis
d78fc53577
ci: Fix bad comparison 2025-05-01 21:27:12 +01:00
Jade Ellis
e3ae024ed3
chore: Link to Matrix rooms directly 2025-05-01 21:23:37 +01:00
Jade Ellis
fb9d4c30f4
feat: Prefill server name in federation test 2025-05-01 21:23:37 +01:00
Jade Ellis
cbcf4300df
ci: Cache timelord-cli to avoid unnecesary compilation 2025-05-01 21:23:37 +01:00
Jade Ellis
a98da7d942
refactor: Move git version info gather in into a build script 2025-05-01 00:38:35 +01:00
Jade Ellis
e1655edd83
feat: HTML default page 2025-04-30 22:31:25 +01:00
24 changed files with 571 additions and 41 deletions

View file

@ -11,7 +11,7 @@ docker/
*.iml
# Git folder
.git
# .git
.gitea
.gitlab
.github

View file

@ -80,17 +80,29 @@ jobs:
run: echo '${{ toJSON(fromJSON(needs.define-variables.outputs.build_matrix)) }}'
- name: Echo matrix
run: echo '${{ toJSON(matrix) }}'
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- run: |
if ! command -v rustup &> /dev/null ; then
curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --default-toolchain none -y
echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
fi
- uses: https://github.com/cargo-bins/cargo-binstall@main
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Cache timelord-cli installation
id: cache-timelord-bin
uses: actions/cache@v3
with:
path: ~/.cargo/bin/timelord
key: timelord-cli-v3.0.1
- name: Install timelord-cli
uses: https://github.com/cargo-bins/cargo-binstall@main
if: steps.cache-timelord-bin.outputs.cache-hit != 'true'
- run: cargo binstall timelord-cli@3.0.1
if: steps.cache-timelord-bin.outputs.cache-hit != 'true'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Set up QEMU
@ -143,7 +155,10 @@ jobs:
context: .
file: "docker/Dockerfile"
build-args: |
CONDUWUIT_VERSION_EXTRA=${{ env.COMMIT_SHORT_SHA }}
GIT_COMMIT_HASH=${{ github.sha }})
GIT_COMMIT_HASH_SHORT=${{ env.COMMIT_SHORT_SHA }})
GIT_REMOTE_URL=${{github.event.repository.html_url }}
GIT_REMOTE_COMMIT_URL=${{github.event.head_commit.url }}
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
@ -199,7 +214,7 @@ jobs:
type=semver,pattern=v{{version}}
type=semver,pattern=v{{major}}.{{minor}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.0.') }}
type=semver,pattern=v{{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) 1= github.ref && 'branch-' || '' }}
type=ref,event=branch,prefix=${{ format('refs/heads/{0}', github.event.repository.default_branch) != github.ref && 'branch-' || '' }}
type=ref,event=pr
type=sha,format=long
images: ${{needs.define-variables.outputs.images}}

109
Cargo.lock generated
View file

@ -109,6 +109,48 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a"
[[package]]
name = "askama"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
dependencies = [
"askama_derive",
"itoa",
"percent-encoding",
"serde",
"serde_json",
]
[[package]]
name = "askama_derive"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
dependencies = [
"askama_parser",
"basic-toml",
"memchr",
"proc-macro2",
"quote",
"rustc-hash 2.1.1",
"serde",
"serde_derive",
"syn",
]
[[package]]
name = "askama_parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
dependencies = [
"memchr",
"serde",
"serde_derive",
"winnow",
]
[[package]]
name = "assign"
version = "1.1.1"
@ -415,6 +457,15 @@ version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
[[package]]
name = "basic-toml"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
dependencies = [
"serde",
]
[[package]]
name = "bindgen"
version = "0.69.5"
@ -533,6 +584,9 @@ name = "built"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
dependencies = [
"cargo-lock",
]
[[package]]
name = "bumpalo"
@ -580,6 +634,19 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "cargo-lock"
version = "10.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06acb4f71407ba205a07cb453211e0e6a67b21904e47f6ba1f9589e38f2e454"
dependencies = [
"petgraph",
"semver",
"serde",
"toml",
"url",
]
[[package]]
name = "cargo_toml"
version = "0.21.0"
@ -805,6 +872,13 @@ dependencies = [
"tracing",
]
[[package]]
name = "conduwuit_build_metadata"
version = "0.5.0-rc.5"
dependencies = [
"built",
]
[[package]]
name = "conduwuit_core"
version = "0.5.0-rc.5"
@ -819,6 +893,7 @@ dependencies = [
"checked_ops",
"chrono",
"clap",
"conduwuit_build_metadata",
"conduwuit_macros",
"const-str",
"core_affinity",
@ -904,6 +979,7 @@ dependencies = [
"conduwuit_api",
"conduwuit_core",
"conduwuit_service",
"conduwuit_web",
"const-str",
"futures",
"http",
@ -961,6 +1037,20 @@ dependencies = [
"webpage",
]
[[package]]
name = "conduwuit_web"
version = "0.5.0-rc.5"
dependencies = [
"askama",
"axum",
"conduwuit_build_metadata",
"conduwuit_service",
"futures",
"rand 0.8.5",
"thiserror 2.0.12",
"tracing",
]
[[package]]
name = "console-api"
version = "0.8.1"
@ -1451,6 +1541,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flate2"
version = "1.1.1"
@ -3068,6 +3164,16 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "petgraph"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
dependencies = [
"fixedbitset",
"indexmap 2.8.0",
]
[[package]]
name = "phf"
version = "0.11.3"
@ -4063,6 +4169,9 @@ name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
dependencies = [
"serde",
]
[[package]]
name = "sentry"

View file

@ -626,6 +626,17 @@ package = "conduwuit_macros"
path = "src/macros"
default-features = false
[workspace.dependencies.conduwuit-web]
package = "conduwuit_web"
path = "src/web"
default-features = false
[workspace.dependencies.conduwuit-build-metadata]
package = "conduwuit_build_metadata"
path = "src/build_metadata"
default-features = false
###############################################################################
#
# Release profiles

View file

@ -111,15 +111,9 @@ RUN mkdir /out
FROM toolchain AS builder
# Conduwuit version info
ARG COMMIT_SHA=
ARG CONDUWUIT_VERSION_EXTRA=
ENV CONDUWUIT_VERSION_EXTRA=$CONDUWUIT_VERSION_EXTRA
RUN <<EOF
if [ -z "${CONDUWUIT_VERSION_EXTRA}" ]; then
echo "CONDUWUIT_VERSION_EXTRA='$(set -e; git rev-parse --short ${COMMIT_SHA:-HEAD} || echo unknown revision)'" >> /etc/environment
fi
EOF
# Get source
COPY . .
ARG TARGETPLATFORM
@ -127,8 +121,20 @@ ARG TARGETPLATFORM
RUN cat /etc/environment
RUN xx-cargo --print-target-triple
# Get source
COPY . .
# Conduwuit version info
ARG GIT_COMMIT_HASH=
ARG GIT_COMMIT_HASH_SHORT=
ARG GIT_REMOTE_URL=
ARG GIT_REMOTE_COMMIT_URL=
ARG CONDUWUIT_VERSION_EXTRA=
ARG CONTINUWUITY_VERSION_EXTRA=
ENV GIT_COMMIT_HASH=$GIT_COMMIT_HASH
ENV GIT_COMMIT_HASH_SHORT=$GIT_COMMIT_HASH_SHORT
ENV GIT_REMOTE_URL=$GIT_REMOTE_URL
ENV GIT_REMOTE_COMMIT_URL=$GIT_REMOTE_COMMIT_URL
ENV CONDUWUIT_VERSION_EXTRA=$CONDUWUIT_VERSION_EXTRA
ENV CONTINUWUITY_VERSION_EXTRA=$CONTINUWUITY_VERSION_EXTRA
# Build the binary
RUN --mount=type=cache,target=/usr/local/cargo/registry \

View file

@ -130,7 +130,8 @@ buildDepsOnlyEnv =
});
buildPackageEnv = {
CONDUWUIT_VERSION_EXTRA = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
GIT_COMMIT_HASH = inputs.self.rev or inputs.self.dirtyRev or "";
GIT_COMMIT_HASH_SHORT = inputs.self.shortRev or inputs.self.dirtyShortRev or "";
} // buildDepsOnlyEnv // {
# Only needed in static stdenv because these are transitive dependencies of rocksdb
CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS

View file

@ -143,7 +143,10 @@ pub(crate) async fn get_message_events_route(
if let Some(registration) = body.appservice_info.as_ref() {
<&DeviceId>::from(registration.registration.id.as_str())
} else {
panic!("No device_id provided and no appservice registration found, this should be unreachable");
panic!(
"No device_id provided and no appservice registration found, this \
should be unreachable"
);
},
},
room_id,

View file

@ -3,7 +3,6 @@ mod auth;
mod handler;
mod request;
mod response;
pub mod state;
use std::str::FromStr;
@ -13,10 +12,11 @@ use axum::{
routing::{any, get, post},
};
use conduwuit::{Server, err};
pub(super) use conduwuit_service::state::State;
use http::{Uri, uri};
use self::handler::RouterExt;
pub(super) use self::{args::Args as Ruma, response::RumaResponse, state::State};
pub(super) use self::{args::Args as Ruma, response::RumaResponse};
use crate::{client, server};
pub fn build(router: Router<State>, server: &Server) -> Router<State> {

View file

@ -0,0 +1,34 @@
[package]
name = "conduwuit_build_metadata"
categories.workspace = true
description.workspace = true
edition.workspace = true
keywords.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true
version.workspace = true
build = "build.rs"
# [[bin]]
# path = "main.rs"
# name = "conduwuit_build_metadata"
[lib]
path = "mod.rs"
crate-type = [
"rlib",
# "dylib",
]
[features]
[dependencies]
[build-dependencies]
built = {version = "0.7", features = ["cargo-lock", "dependency-tree"]}
[lints]
workspace = true

View file

@ -0,0 +1,92 @@
use std::process::Command;
fn run_git_command(args: &[&str]) -> Option<String> {
Command::new("git")
.args(args)
.output()
.ok()
.filter(|output| output.status.success())
.and_then(|output| String::from_utf8(output.stdout).ok())
.map(|s| s.trim().to_owned())
.filter(|s| !s.is_empty())
}
fn get_env(env_var: &str) -> Option<String> {
match std::env::var(env_var) {
| Ok(val) if !val.is_empty() => Some(val),
| _ => None,
}
}
fn main() {
// built gets the default crate from the workspace. Not sure if this is intended
// behavior, but it's what we want.
built::write_built_file().expect("Failed to acquire build-time information");
// --- Git Information ---
let mut commit_hash = None;
let mut commit_hash_short = None;
let mut remote_url_web = None;
// Get full commit hash
if let Some(hash) =
get_env("GIT_COMMIT_HASH").or_else(|| run_git_command(&["rev-parse", "HEAD"]))
{
println!("cargo:rustc-env=GIT_COMMIT_HASH={hash}");
commit_hash = Some(hash);
}
// Get short commit hash
if let Some(short_hash) = get_env("GIT_COMMIT_HASH_SHORT")
.or_else(|| run_git_command(&["rev-parse", "--short", "HEAD"]))
{
println!("cargo:rustc-env=GIT_COMMIT_HASH_SHORT={short_hash}");
commit_hash_short = Some(short_hash);
}
// Get remote URL and convert to web URL
if let Some(remote_url_raw) = get_env("GIT_REMOTE_URL")
.or_else(|| run_git_command(&["config", "--get", "remote.origin.url"]))
{
println!("cargo:rustc-env=GIT_REMOTE_URL={remote_url_raw}");
let web_url = if remote_url_raw.starts_with("https://") {
remote_url_raw.trim_end_matches(".git").to_owned()
} else if remote_url_raw.starts_with("git@") {
remote_url_raw
.trim_end_matches(".git")
.replacen(':', "/", 1)
.replacen("git@", "https://", 1)
} else if remote_url_raw.starts_with("ssh://") {
remote_url_raw
.trim_end_matches(".git")
.replacen("git@", "", 1)
.replacen("ssh:", "https:", 1)
} else {
// Assume it's already a web URL or unknown format
remote_url_raw
};
println!("cargo:rustc-env=GIT_REMOTE_WEB_URL={web_url}");
remote_url_web = Some(web_url);
}
// Construct remote commit URL
if let Some(remote_commit_url) = get_env("GIT_REMOTE_COMMIT_URL") {
println!("cargo:rustc-env=GIT_REMOTE_COMMIT_URL={remote_commit_url}");
} else if let (Some(base_url), Some(hash)) =
(&remote_url_web, commit_hash.as_ref().or(commit_hash_short.as_ref()))
{
let commit_page = format!("{base_url}/commit/{hash}");
println!("cargo:rustc-env=GIT_REMOTE_COMMIT_URL={commit_page}");
}
// --- Rerun Triggers ---
// Rerun if the git HEAD changes
println!("cargo:rerun-if-changed=.git/HEAD");
// Rerun if the ref pointed to by HEAD changes (e.g., new commit on branch)
if let Some(ref_path) = run_git_command(&["symbolic-ref", "--quiet", "HEAD"]) {
println!("cargo:rerun-if-changed=.git/{ref_path}");
}
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH");
println!("cargo:rerun-if-env-changed=GIT_COMMIT_HASH_SHORT");
println!("cargo:rerun-if-env-changed=GIT_REMOTE_URL");
println!("cargo:rerun-if-env-changed=GIT_REMOTE_COMMIT_URL");
}

23
src/build_metadata/mod.rs Normal file
View file

@ -0,0 +1,23 @@
pub mod built {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
}
pub static GIT_COMMIT_HASH: Option<&str> = option_env!("GIT_COMMIT_HASH");
pub static GIT_COMMIT_HASH_SHORT: Option<&str> = option_env!("GIT_COMMIT_HASH_SHORT");
// this would be a lot better if Option::or was const.
pub static VERSION_EXTRA: Option<&str> =
if let v @ Some(_) = option_env!("CONTINUWUITY_VERSION_EXTRA") {
v
} else if let v @ Some(_) = option_env!("CONDUWUIT_VERSION_EXTRA") {
v
} else if let v @ Some(_) = option_env!("CONDUIT_VERSION_EXTRA") {
v
} else {
GIT_COMMIT_HASH_SHORT
};
pub static GIT_REMOTE_WEB_URL: Option<&str> = option_env!("GIT_REMOTE_WEB_URL");
pub static GIT_REMOTE_COMMIT_URL: Option<&str> = option_env!("GIT_REMOTE_COMMIT_URL");
// TODO: Mark dirty builds within the version string

View file

@ -67,6 +67,7 @@ checked_ops.workspace = true
chrono.workspace = true
clap.workspace = true
conduwuit-macros.workspace = true
conduwuit-build-metadata.workspace = true
const-str.workspace = true
core_affinity.workspace = true
ctor.workspace = true

View file

@ -26,13 +26,6 @@ pub fn user_agent() -> &'static str { USER_AGENT.get_or_init(init_user_agent) }
fn init_user_agent() -> String { format!("{}/{}", name(), version()) }
fn init_version() -> String {
option_env!("CONDUWUIT_VERSION_EXTRA")
.or(option_env!("CONDUIT_VERSION_EXTRA"))
.map_or(SEMANTIC.to_owned(), |extra| {
if extra.is_empty() {
SEMANTIC.to_owned()
} else {
format!("{SEMANTIC} ({extra})")
}
})
conduwuit_build_metadata::VERSION_EXTRA
.map_or(SEMANTIC.to_owned(), |extra| format!("{SEMANTIC} ({extra})"))
}

View file

@ -103,6 +103,7 @@ conduwuit-admin.workspace = true
conduwuit-api.workspace = true
conduwuit-core.workspace = true
conduwuit-service.workspace = true
conduwuit-web.workspace = true
const-str.workspace = true
futures.workspace = true
http.workspace = true

View file

@ -6,8 +6,7 @@ use axum::{
};
use axum_client_ip::SecureClientIpSource;
use conduwuit::{Result, Server, debug, error};
use conduwuit_api::router::state::Guard;
use conduwuit_service::Services;
use conduwuit_service::{Services, state::Guard};
use http::{
HeaderValue, Method, StatusCode,
header::{self, HeaderName},

View file

@ -1,9 +1,8 @@
use std::sync::Arc;
use axum::{Router, response::IntoResponse, routing::get};
use axum::{Router, response::IntoResponse};
use conduwuit::Error;
use conduwuit_api::router::{state, state::Guard};
use conduwuit_service::Services;
use conduwuit_service::{Services, state, state::Guard};
use http::{StatusCode, Uri};
use ruma::api::client::error::ErrorKind;
@ -11,7 +10,7 @@ pub(crate) fn build(services: &Arc<Services>) -> (Router, Guard) {
let router = Router::<state::State>::new();
let (state, guard) = state::create(services.clone());
let router = conduwuit_api::router::build(router, &services.server)
.route("/", get(it_works))
.merge(conduwuit_web::build())
.fallback(not_found)
.with_state(state);
@ -21,5 +20,3 @@ pub(crate) fn build(services: &Arc<Services>) -> (Router, Guard) {
async fn not_found(_uri: Uri) -> impl IntoResponse {
Error::Request(ErrorKind::Unrecognized, "Not Found".into(), StatusCode::NOT_FOUND)
}
async fn it_works() -> &'static str { "hewwo from conduwuit woof!" }

View file

@ -5,6 +5,7 @@ mod manager;
mod migrations;
mod service;
pub mod services;
pub mod state;
pub mod account_data;
pub mod admin;

View file

@ -1,6 +1,6 @@
use std::{ops::Deref, sync::Arc};
use conduwuit_service::Services;
use crate::Services;
#[derive(Clone, Copy)]
pub struct State {

35
src/web/Cargo.toml Normal file
View file

@ -0,0 +1,35 @@
[package]
name = "conduwuit_web"
categories.workspace = true
description.workspace = true
edition.workspace = true
keywords.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true
version.workspace = true
[lib]
path = "mod.rs"
crate-type = [
"rlib",
# "dylib",
]
[features]
[dependencies]
conduwuit-build-metadata.workspace = true
conduwuit-service.workspace = true
askama = "0.14.0"
axum.workspace = true
futures.workspace = true
tracing.workspace = true
rand.workspace = true
thiserror.workspace = true
[lints]
workspace = true

68
src/web/css/index.css Normal file
View file

@ -0,0 +1,68 @@
:root {
color-scheme: light;
--font-stack: sans-serif;
--background-color: #fff;
--text-color: #000;
--bg: oklch(0.76 0.0854 317.27);
--panel-bg: oklch(0.91 0.042 317.27);
--name-lightness: 0.45;
@media (prefers-color-scheme: dark) {
color-scheme: dark;
--text-color: #fff;
--bg: oklch(0.15 0.042 317.27);
--panel-bg: oklch(0.24 0.03 317.27);
--name-lightness: 0.8;
}
--c1: oklch(0.44 0.177 353.06);
--c2: oklch(0.59 0.158 150.88);
--normal-font-size: 1rem;
--small-font-size: 0.8rem;
}
body {
color: var(--text-color);
font-family: var(--font-stack);
margin: 0;
padding: 0;
display: grid;
place-items: center;
min-height: 100vh;
}
html {
background-color: var(--bg);
background-image: linear-gradient(
70deg,
oklch(from var(--bg) l + 0.2 c h),
oklch(from var(--bg) l - 0.2 c h)
);
font-size: 16px;
}
.panel {
width: min(clamp(24rem, 12rem + 40vw, 48rem), 100vw);
border-radius: 15px;
background-color: var(--panel-bg);
padding-inline: 1.5rem;
padding-block: 1rem;
box-shadow: 0 0.25em 0.375em hsla(0, 0%, 0%, 0.1);
}
.project-name {
text-decoration: none;
background: linear-gradient(
130deg,
oklch(from var(--c1) var(--name-lightness) c h),
oklch(from var(--c2) var(--name-lightness) c h)
);
background-clip: text;
color: transparent;
filter: brightness(1.2);
}

73
src/web/mod.rs Normal file
View file

@ -0,0 +1,73 @@
use askama::Template;
use axum::{
Router,
extract::State,
http::{StatusCode, header},
response::{Html, IntoResponse, Response},
routing::get,
};
use conduwuit_build_metadata::{GIT_REMOTE_COMMIT_URL, GIT_REMOTE_WEB_URL, VERSION_EXTRA};
use conduwuit_service::state;
pub fn build() -> Router<state::State> {
let router = Router::<state::State>::new();
router.route("/", get(index_handler))
}
async fn index_handler(
State(services): State<state::State>,
) -> Result<impl IntoResponse, WebError> {
#[derive(Debug, Template)]
#[template(path = "index.html.j2")]
struct Tmpl<'a> {
nonce: &'a str,
server_name: &'a str,
}
let nonce = rand::random::<u64>().to_string();
let template = Tmpl {
nonce: &nonce,
server_name: services.config.server_name.as_str(),
};
Ok((
[(header::CONTENT_SECURITY_POLICY, format!("default-src 'none' 'nonce-{nonce}';"))],
Html(template.render()?),
))
}
#[derive(Debug, thiserror::Error)]
enum WebError {
#[error("Failed to render template: {0}")]
Render(#[from] askama::Error),
}
impl IntoResponse for WebError {
fn into_response(self) -> Response {
#[derive(Debug, Template)]
#[template(path = "error.html.j2")]
struct Tmpl<'a> {
nonce: &'a str,
err: WebError,
}
let nonce = rand::random::<u64>().to_string();
let status = match &self {
| Self::Render(_) => StatusCode::INTERNAL_SERVER_ERROR,
};
let tmpl = Tmpl { nonce: &nonce, err: self };
if let Ok(body) = tmpl.render() {
(
status,
[(
header::CONTENT_SECURITY_POLICY,
format!("default-src 'none' 'nonce-{nonce}';"),
)],
Html(body),
)
.into_response()
} else {
(status, "Something went wrong").into_response()
}
}
}

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{% block title %}Continuwuity{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css" nonce="{{ nonce }}">
/*<![CDATA[*/
{{ include_str !("css/index.css") | safe }}
/*]]>*/
</style>
</head>
<body>
<main>{%~ block content %}{% endblock ~%}</main>
{%~ block footer ~%}
<footer>
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a>
{%~ if let Some(version_info) = VERSION_EXTRA ~%}
{%~ if let Some(url) = GIT_REMOTE_COMMIT_URL.or(GIT_REMOTE_WEB_URL) ~%}
(<a href="{{ url }}">{{ version_info }}</a>)
{%~ else ~%}
({{ version_info }})
{%~ endif ~%}
{%~ endif ~%}</p>
</footer>
{%~ endblock ~%}
</body>
</html>

View file

@ -0,0 +1,20 @@
{% extends "_layout.html.j2" %}
{%- block title -%}
Server Error
{%- endblock -%}
{%- block content -%}
<h1>
{%- match err -%}
{% else -%} 500: Internal Server Error
{%- endmatch -%}
</h1>
{%- match err -%}
{% when WebError::Render(err) -%}
<pre>{{ err }}</pre>
{% else -%} <p>An error occurred</p>
{%- endmatch -%}
{%- endblock -%}

View file

@ -0,0 +1,16 @@
{% extends "_layout.html.j2" %}
{%- block content -%}
<div class="orb"></div>
<div class="panel">
<h1>Welcome to <a class="project-name" href="https://continuwuity.org">Continuwuity</a>!</h1>
<p>Continuwuity is successfully installed and working. </p>
<p>To get started, you can:</p>
<ul>
<li>Read the <a href="https://continuwuity.org/introduction">documentation</a></li>
<li>Join the <a href="https://matrix.to/#/#continuwuity:continuwuity.org">Continuwuity Matrix room</a> or <a href="https://matrix.to/#/#space:continuwuity.org">space</a></li>
<li>Log in with a <a href="https://matrix.org/ecosystem/clients/">client</a></li>
<li>Ensure <a href="https://federationtester.matrix.org/#{{ server_name }}">federation</a> works</li>
</ul>
</div>
{%- endblock content -%}