### get example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_config/struct.ClientsConfig.html Demonstrates accessing elements or subslices using the get method. ```rust let v = [10, 40, 30]; assert_eq!(Some(&40), v.get(1)); assert_eq!(Some(&[10, 40][..]), v.get(0..2)); assert_eq!(None, v.get(3)); assert_eq!(None, v.get(0..4)); ``` -------------------------------- ### Install sqlx-cli Source: https://element-hq.github.io/matrix-authentication-service/print.html Installs the `cargo-sqlx` CLI tool. ```bash cargo install sqlx-cli ``` -------------------------------- ### Box::into_raw Examples Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/type.BoxRng.html?search= Examples demonstrating how to consume a Box and manage the resulting raw pointer. ```rust let x = Box::new(String::from("Hello")); let ptr = Box::into_raw(x); let x = unsafe { Box::from_raw(ptr) }; ``` ```rust use std::alloc::{dealloc, Layout}; use std::ptr; let x = Box::new(String::from("Hello")); let ptr = Box::into_raw(x); unsafe { ptr::drop_in_place(ptr); dealloc(ptr as *mut u8, Layout::new::()); } ``` ```rust let x = Box::new(String::from("Hello")); let ptr = Box::into_raw(x); unsafe { drop(Box::from_raw(ptr)); } ``` -------------------------------- ### Run the authentication service with mas-cli server Source: https://element-hq.github.io/matrix-authentication-service/reference/cli/server.html Starts the authentication service. The example shows the command `mas-cli server` and its expected output, including the listening address http://0.0.0.0:8080. ```bash mas-cli server ``` ```text INFO mas_cli::server: Starting task scheduler INFO mas_core::templates: Loading builtin templates INFO mas_cli::server: Listening on http://0.0.0.0:8080 ``` -------------------------------- ### Setup and List Upstream OAuth Links Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/admin/v1/upstream_oauth_links/list.rs.html This snippet demonstrates creating multiple upstream OAuth links, associating them with users, and performing a GET request to list them. ```rust &mut rng, &state.clock, &provider1, "subject1".to_owned(), Some("alice@acme".to_owned()), ) .await .unwrap(); repo.upstream_oauth_link() .associate_to_user(&link1, &alice) .await .unwrap(); let link2 = repo .upstream_oauth_link() .add( &mut rng, &state.clock, &provider2, "subject2".to_owned(), Some("alice@example".to_owned()), ) .await .unwrap(); repo.upstream_oauth_link() .associate_to_user(&link2, &alice) .await .unwrap(); let link3 = repo .upstream_oauth_link() .add( &mut rng, &state.clock, &provider1, "subject3".to_owned(), Some("bob@acme".to_owned()), ) .await .unwrap(); repo.upstream_oauth_link() .associate_to_user(&link3, &bob) .await .unwrap(); repo.save().await.unwrap(); let request = Request::get("/api/admin/v1/upstream-oauth-links") .bearer(&token) .empty(); let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); assert_json_snapshot!(body, @r#" { "meta": { "count": 3 }, "data": [ { "type": "upstream-oauth-link", "id": "01FSHN9AG0AQZQP8DX40GD59PW", "attributes": { "created_at": "2022-01-16T14:40:00Z", "provider_id": "01FSHN9AG09NMZYX8MFYH578R9", "subject": "subject1", "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", "human_account_name": "alice@acme" }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" }, "meta": { "page": { "cursor": "01FSHN9AG0AQZQP8DX40GD59PW" } } }, { "type": "upstream-oauth-link", "id": "01FSHN9AG0PJZ6DZNTAA1XKPT4", "attributes": { "created_at": "2022-01-16T14:40:00Z", "provider_id": "01FSHN9AG09NMZYX8MFYH578R9", "subject": "subject3", "user_id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4", "human_account_name": "bob@acme" }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4" }, "meta": { "page": { "cursor": "01FSHN9AG0PJZ6DZNTAA1XKPT4" } } }, { "type": "upstream-oauth-link", "id": "01FSHN9AG0QHEHKX2JNQ2A2D07", "attributes": { "created_at": "2022-01-16T14:40:00Z", "provider_id": "01FSHN9AG0KEPHYQQXW9XPTX6Z", "subject": "subject2", "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", "human_account_name": "alice@example" }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07" }, "meta": { "page": { "cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07" } } } ], "links": { "self": "/api/admin/v1/upstream-oauth-links?page[first]=10", "first": "/api/admin/v1/upstream-oauth-links?page[first]=10", "last": "/api/admin/v1/upstream-oauth-links?page[last]=10" } } "#); ``` -------------------------------- ### Setup and Request Personal Sessions Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/admin/v1/personal_sessions/list.rs.html?search= Initializes a personal access token, saves the repository state, and performs a GET request to the admin personal sessions endpoint. ```rust repo.personal_access_token() .add( &mut rng, &state.clock, &personal_session, "mpt_meow", Some(Duration::days(14)), ) .await .unwrap(); repo.save().await.unwrap(); let token = state.token_with_scope("urn:mas:admin").await; let request = Request::get("/api/admin/v1/personal-sessions") .bearer(&token) .empty(); let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); ``` -------------------------------- ### Test Module Setup Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/oauth2_types/requests.rs.html Imports and module setup for the test module, including serde_json and test utilities. ```rust #[cfg(test)] mod tests { use serde_json::json; use super::*; use crate::{scope::OPENID, test_utils::assert_serde_json}; ``` -------------------------------- ### Manage and Query Application Sessions Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_storage_pg/app_session.rs.html This example demonstrates listing sessions, creating an OAuth2 client and session, and verifying session counts and states. It also shows how to finish an active session and query sessions by device. ```rust let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); assert_eq!(finished_list.edges.len(), 1); assert_eq!( finished_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); // Start an OAuth2 session let client = repo .oauth2_client() .add( &mut rng, &clock, vec!["https://example.com/redirect".parse().unwrap()], None, None, None, vec![GrantType::AuthorizationCode], Some("First client".to_owned()), Some("https://example.com/logo.png".parse().unwrap()), Some("https://example.com/".parse().unwrap()), Some("https://example.com/policy".parse().unwrap()), Some("https://example.com/tos".parse().unwrap()), Some("https://example.com/jwks.json".parse().unwrap()), None, None, None, None, None, Some("https://example.com/login".parse().unwrap()), ) .await .unwrap(); let device2 = Device::generate(&mut rng); let scope: Scope = [OPENID] .into_iter() .chain(device2.to_scope_token().unwrap().into_iter()) .collect(); // We're moving the clock forward by 1 minute between each session to ensure // we're getting consistent ordering in lists. clock.advance(Duration::try_minutes(1).unwrap()); let oauth_session = repo .oauth2_session() .add(&mut rng, &clock, &client, Some(&user), None, scope) .await .unwrap(); assert_eq!(repo.app_session().count(all).await.unwrap(), 2); assert_eq!(repo.app_session().count(active).await.unwrap(), 1); assert_eq!(repo.app_session().count(finished).await.unwrap(), 1); let full_list = repo.app_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 2); assert_eq!( full_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); assert_eq!( full_list.edges[1].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); let active_list = repo.app_session().list(active, pagination).await.unwrap(); assert_eq!(active_list.edges.len(), 1); assert_eq!( active_list.edges[0].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); assert_eq!(finished_list.edges.len(), 1); assert_eq!( finished_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); // Finish the session let oauth_session = repo .oauth2_session() .finish(&clock, oauth_session) .await .unwrap(); assert_eq!(repo.app_session().count(all).await.unwrap(), 2); assert_eq!(repo.app_session().count(active).await.unwrap(), 0); assert_eq!(repo.app_session().count(finished).await.unwrap(), 2); let full_list = repo.app_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 2); assert_eq!( full_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); assert_eq!( full_list.edges[1].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); let active_list = repo.app_session().list(active, pagination).await.unwrap(); assert!(active_list.edges.is_empty()); let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); assert_eq!(finished_list.edges.len(), 2); assert_eq!( finished_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); assert_eq!( full_list.edges[1].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); // Query by device let filter = AppSessionFilter::new().for_device(&device); assert_eq!(repo.app_session().count(filter).await.unwrap(), 1); let list = repo.app_session().list(filter, pagination).await.unwrap(); assert_eq!(list.edges.len(), 1); assert_eq!( ``` -------------------------------- ### Account recovery start handlers (get and post) in Rust Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/views/recovery/start.rs.html Rust handler for the account recovery start page. It defines the StartRecoveryForm struct and implements both GET and POST handlers. The GET handler renders the recovery start form or redirects if a session is active; the POST handler validates the email, checks rate limits, and re-renders the form with errors if invalid. ```rust // Copyright 2024, 2025 New Vector Ltd. // Copyright 2024 The Matrix.org Foundation C.I.C. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. use std::str::FromStr; use axum::{ Form, extract::State, response::{Html, IntoResponse, Response}, }; use axum_extra::typed_header::TypedHeader; use lettre::Address; use mas_axum_utils::{ InternalError, SessionInfoExt, cookies::CookieJar, csrf::{CsrfExt, ProtectedForm}, }; use mas_data_model::{BoxClock, BoxRng, SiteConfig}; use mas_router::UrlBuilder; use mas_storage::{ BoxRepository, queue::{QueueJobRepositoryExt as _, SendAccountRecoveryEmailsJob}, }; use mas_templates::{ EmptyContext, FieldError, FormError, FormState, RecoveryStartContext, RecoveryStartFormField, TemplateContext, Templates, }; use serde::{Deserialize, Serialize}; use crate::{BoundActivityTracker, Limiter, PreferredLanguage, RequesterFingerprint}; #[derive(Deserialize, Serialize)] pub(crate) struct StartRecoveryForm { email: String, } pub(crate) async fn get( mut rng: BoxRng, clock: BoxClock, mut repo: BoxRepository, State(site_config): State, State(templates): State, State(url_builder): State, PreferredLanguage(locale): PreferredLanguage, cookie_jar: CookieJar, ) -> Result { if !site_config.account_recovery_allowed { let context = EmptyContext.with_language(locale); let rendered = templates.render_recovery_disabled(&context)?; return Ok((cookie_jar, Html(rendered)).into_response()); } let (session_info, cookie_jar) = cookie_jar.session_info(); let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let maybe_session = session_info.load_active_session(&mut repo).await?; if maybe_session.is_some() { // TODO: redirect to continue whatever action was going on return Ok((cookie_jar, url_builder.redirect(&mas_router::Index)).into_response()); } let context = RecoveryStartContext::new() .with_csrf(csrf_token.form_value()) .with_language(locale); repo.save().await?; let rendered = templates.render_recovery_start(&context)?; Ok((cookie_jar, Html(rendered)).into_response()) } pub(crate) async fn post( mut rng: BoxRng, clock: BoxClock, mut repo: BoxRepository, user_agent: TypedHeader, activity_tracker: BoundActivityTracker, State(site_config): State, State(templates): State, State(url_builder): State, (State(limiter), requester): (State, RequesterFingerprint), PreferredLanguage(locale): PreferredLanguage, cookie_jar: CookieJar, Form(form): Form>, ) -> Result { if !site_config.account_recovery_allowed { let context = EmptyContext.with_language(locale); let rendered = templates.render_recovery_disabled(&context)?; return Ok((cookie_jar, Html(rendered)).into_response()); } let (session_info, cookie_jar) = cookie_jar.session_info(); let (csrf_token, cookie_jar) = cookie_jar.csrf_token(&clock, &mut rng); let maybe_session = session_info.load_active_session(&mut repo).await?; if maybe_session.is_some() { // TODO: redirect to continue whatever action was going on return Ok((cookie_jar, url_builder.redirect(&mas_router::Index)).into_response()); } let user_agent = user_agent.as_str().to_owned(); let ip_address = activity_tracker.ip(); let form = cookie_jar.verify_form(&clock, form)?; let mut form_state = FormState::from_form(&form); if Address::from_str(&form.email).is_err() { form_state = form_state.with_error_on_field(RecoveryStartFormField::Email, FieldError::Invalid); } if form_state.is_valid() { // Check the rate limit if we are about to process the form if let Err(e) = limiter.check_account_recovery(requester, &form.email) { tracing::warn!(error = &e as &dyn std::error::Error); form_state.add_error_on_form(FormError::RateLimitExceeded); } } if !form_state.is_valid() { repo.save().await?; let context = RecoveryStartContext::new() .with_form_state(form_state) .with_csrf(csrf_token.form_value()) .with_language(locale); let rendered = templates.render_recovery_start(&context)?; ``` -------------------------------- ### Build from source Source: https://element-hq.github.io/matrix-authentication-service/setup/installation.html Build the service from source. Requires the Rust toolchain, Node.js with corepack, and the Open Policy Agent binary (or Docker). Steps: clone the repo, build the frontend, build the OPA policies (optionally with Docker), compile the CLI, and copy the binary to a directory in $PATH. ```bash git clone https://github.com/element-hq/matrix-authentication-service.git cd matrix-authentication-service ``` ```bash corepack enable pnpm install # installs deps for the workspace; run from the repo root cd frontend pnpm run build cd .. ``` ```bash cd policies make cd .. ``` ```bash cd policies make DOCKER=1 cd .. ``` ```bash cargo build --release ``` ```bash cp ./target/release/mas-cli ~/.local/bin # Copy the binary somewhere in $PATH mas-cli --help # Should display the help message ``` -------------------------------- ### Setup User and Perform Password Login Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/oauth2/introspection.rs.html Initializes a user in the repository, provisions them, sets a password, and performs a login request to obtain access and refresh tokens. ```rust let mut repo = state.repository().await.unwrap(); let user = repo .user() .add(&mut state.rng(), &state.clock, "alice".to_owned()) .await .unwrap(); state .homeserver_connection .provision_user(&ProvisionRequest::new(&user.username, &user.sub, false)) .await .unwrap(); let (version, hashed_password) = state .password_manager .hash(&mut state.rng(), Zeroizing::new("password".to_owned())) .await .unwrap(); repo.user_password() .add( &mut state.rng(), &state.clock, &user, version, hashed_password, None, ) .await .unwrap(); repo.save().await.unwrap(); // Now do a password flow to get an access token and a refresh token let request = Request::post("/_matrix/client/v3/login").json(json!({ "type": "m.login.password", "refresh_token": true, "identifier": { "type": "m.id.user", "user": "alice", }, "password": "password", })); let response = state.request(request).await; response.assert_status(StatusCode::OK); let response: serde_json::Value = response.json(); let access_token = response["access_token"].as_str().unwrap(); let refresh_token = response["refresh_token"].as_str().unwrap(); let device_id = response["device_id"].as_str().unwrap(); let expected_scope: Scope = format!("urn:matrix:org.matrix.msc2967.client:api:* urn:matrix:org.matrix.msc2967.client:device:{device_id} urn:matrix:client:api:* urn:matrix:client:device:{device_id}") .parse() .unwrap(); ``` -------------------------------- ### trim_start_matches example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/struct.UserAgent.html?search= Example demonstrating the use of trim_start_matches to remove a set of characters from the start of a string. ```rust let x: &[_] = &['1', '2']; assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12"); ``` -------------------------------- ### BTreeSet get method example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_oidc_client/types/response_type/struct.ResponseType.html Demonstrates retrieving a reference to an element in the set using the get method. ```rust use std::collections::BTreeSet; let set = BTreeSet::from([1, 2, 3]); assert_eq!(set.get(&2), Some(&2)); assert_eq!(set.get(&4), None); ``` -------------------------------- ### Build the frontend with pnpm Source: https://element-hq.github.io/matrix-authentication-service/development/contributing.html Enable corepack, install dependencies, and build the frontend from the repo root. ```bash corepack enable # one-time; picks pnpm@11 from the root package.json pnpm install # Install dependencies for the whole workspace (run from the repo root) cd frontend pnpm run build # Build the frontend cd .. ``` -------------------------------- ### Database configuration section start Source: https://element-hq.github.io/matrix-authentication-service/print.html Starts the database configuration section for connecting to PostgreSQL. The snippet is incomplete in the source, showing only the 'database:' key. ```yaml database: ``` -------------------------------- ### Get Synapse admin token Source: https://element-hq.github.io/matrix-authentication-service/print.html Example invocation to get an access token for the Synapse admin API. ```bash sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:matrix:org.matrix.msc2967.client:api:* urn:synapse:admin:* ``` -------------------------------- ### Get MAS admin token Source: https://element-hq.github.io/matrix-authentication-service/print.html Example invocation to get an access token for the MAS admin API. ```bash sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:mas:admin ``` -------------------------------- ### Provision client, user, and OAuth session, then generate token pair Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/oauth2/introspection.rs.html Sets up the test environment by registering an OAuth2 client, creating a user, provisioning the user on the homeserver, creating a browser session and OAuth session, and generating an access token and refresh token pair. The token pair is generated with a 5-minute lifetime and saved to the repository. ```rust // Provision a client which will be used to generate tokens let request = Request::post(OAuth2RegistrationEndpoint::PATH).json(json!({ "client_uri": "https://client.com/", "redirect_uris": ["https://client.com/"], "response_types": ["code"], "grant_types": ["authorization_code", "refresh_token"], "token_endpoint_auth_method": "none", })); let response = state.request(request).await; response.assert_status(StatusCode::CREATED); let ClientRegistrationResponse { client_id, .. } = response.json(); let mut repo = state.repository().await.unwrap(); // Provision a user and an oauth session let user = repo .user() .add(&mut state.rng(), &state.clock, "alice".to_owned()) .await .unwrap(); state .homeserver_connection .provision_user(&ProvisionRequest::new(&user.username, &user.sub, false)) .await .unwrap(); let client = repo .oauth2_client() .find_by_client_id(&client_id) .await .unwrap() .unwrap(); let browser_session = repo .browser_session() .add(&mut state.rng(), &state.clock, &user, None) .await .unwrap(); let session = repo .oauth2_session() .add_from_browser_session( &mut state.rng(), &state.clock, &client, &browser_session, Scope::from_iter([OPENID]), ) .await .unwrap(); let (AccessToken { access_token, .. }, RefreshToken { refresh_token, .. }) = generate_token_pair( &mut state.rng(), &state.clock, &mut repo, &session, Duration::microseconds(5 * 60 * 1000 * 1000), ) .await .unwrap(); repo.save().await.unwrap(); ``` -------------------------------- ### Address::domain example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_email/struct.Address.html?search= Gets the domain portion of an Address using the domain method. The example asserts the returned value. ```rust use lettre::Address; let address = Address::new("user", "email.com")?; assert_eq!(address.domain(), "email.com"); ``` -------------------------------- ### Template loading and environment setup Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_templates/lib.rs.html Loads templates from disk, sets up the minijinja environment with branding and features globals, registers custom functions, and verifies all required templates are present. Returns a translator and environment or a TemplateLoadingError if templates are missing. ```rust env.add_template_owned(relative.as_str().to_owned(), template)?; loaded.insert(relative.as_str().to_owned()); } } } Ok::<_, TemplateLoadingError>((loaded, env)) }) }) .await??; env.add_global("branding", Value::from_object(branding)); env.add_global("features", Value::from_object(features)); self::functions::register( &mut env, url_builder, vite_manifest, Arc::clone(&translator), ); let env = Arc::new(env); let needed: HashSet<_> = TEMPLATES.into_iter().map(ToOwned::to_owned).collect(); debug!(?loaded, ?needed, "Templates loaded"); let missing: HashSet<_> = needed.difference(&loaded).cloned().collect(); if missing.is_empty() { Ok((translator, env)) } else { Err(TemplateLoadingError::MissingTemplates { missing, loaded }) } ``` -------------------------------- ### Address::user example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_email/struct.Address.html?search= Gets the user portion of an Address using the user method. The example asserts the returned value. ```rust use lettre::Address; let address = Address::new("user", "email.com")?; assert_eq!(address.user(), "user"); ``` -------------------------------- ### Run MAS server Source: https://element-hq.github.io/matrix-authentication-service/print.html Starts the MAS server using the specified configuration file. ```bash cargo run -- server -c config.yaml ``` -------------------------------- ### str::len example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/struct.UserAgent.html?search= Shows how to use the len method to get the byte length of a string, including a non-ASCII example. ```rust let len = "foo".len(); assert_eq!(3, len); assert_eq!("ƒoo".len(), 4); // fancy f! assert_eq!("ƒoo".chars().count(), 3); ``` -------------------------------- ### random example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/struct.Ulid.html Gets the random section of a Ulid. The example increments a Ulid and verifies that the random part increases by one. ```rust use ulid::Ulid; let text = "01D39ZY06FGSCTVN4T2V9PKHFZ"; let ulid = Ulid::from_string(text).unwrap(); let ulid_next = ulid.increment().unwrap(); assert_eq!(ulid.random() + 1, ulid_next.random()); ``` -------------------------------- ### Split string with start or end separators Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/struct.UserAgent.html?search= Example showing how separators at the start or end of a string result in empty strings. ```rust let d: Vec<_> = "010".split("0").collect(); assert_eq!(d, &["", "1", ""]); ``` -------------------------------- ### Manually create a Box from scratch using Box::from_raw_in Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/type.BoxRng.html Shows how to manually allocate memory and construct a Box using the system allocator. ```rust #![feature(allocator_api, slice_ptr_get)] use std::alloc::{Allocator, Layout, System}; unsafe { let ptr = System.allocate(Layout::new::())?.as_mut_ptr() as *mut i32; // In general .write is required to avoid attempting to destruct // the (uninitialized) previous contents of `ptr`, though for this // simple example `*ptr = 5` would have worked as well. ptr.write(5); let x = Box::from_raw_in(ptr, System); } ``` -------------------------------- ### Initiate and Fulfill Compat SSO Login Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/compat/login.rs.html?search= Demonstrates starting a compat SSO login flow and fulfilling it using a browser session. ```rust // Start a compat SSO login flow let login = repo .compat_sso_login() .add( &mut state.rng(), &state.clock, token.clone(), "http://example.com/".parse().unwrap(), ) .await .unwrap(); // Advance the flow by fulfilling it with a browser session let browser_session = repo .browser_session() .add(&mut state.rng(), &state.clock, user, None) .await .unwrap(); let _login = repo .compat_sso_login() .fulfill(&state.clock, login, &browser_session) .await .unwrap(); repo.save().await.unwrap(); token } ``` -------------------------------- ### Get combined MAS and Synapse admin token Source: https://element-hq.github.io/matrix-authentication-service/print.html Example invocation to get an access token for both MAS and Synapse admin APIs simultaneously. ```bash sh ./misc/device-code-grant.sh https://synapse.example.com/ urn:matrix:org.matrix.msc2967.client:api:* urn:mas:admin urn:synapse:admin:* ``` -------------------------------- ### timestamp_ms example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/struct.Ulid.html Gets the timestamp section of a Ulid. The example creates a Ulid from the current system time and compares the timestamp to the duration since the Unix epoch. ```rust use std::time::{SystemTime, Duration}; use ulid::Ulid; let dt = SystemTime::now(); let ulid = Ulid::from_datetime(dt); assert_eq!(u128::from(ulid.timestamp_ms()), dt.duration_since(SystemTime::UNIX_EPOCH).unwrap_or(Duration::ZERO).as_millis()); ``` -------------------------------- ### Setup Upstream OAuth Provider, Session, and Link Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/upstream_oauth2/link.rs.html?search= Creates claims imports, signs a JWT ID token, adds a provider, session, and link, then completes the session with the token. ```rust let claims_imports = UpstreamOAuthProviderClaimsImports { localpart: UpstreamOAuthProviderLocalpartPreference { action: mas_data_model::UpstreamOAuthProviderImportAction::Force, template: None, on_conflict: mas_data_model::UpstreamOAuthProviderOnConflict::default(), }, email: UpstreamOAuthProviderImportPreference { action: mas_data_model::UpstreamOAuthProviderImportAction::Force, template: None, }, ..UpstreamOAuthProviderClaimsImports::default() }; let id_token_claims = serde_json::json!({ "preferred_username": "john", "email": "john@example.com", "email_verified": true, }); // Grab a key to sign the id_token // We could generate a key on the fly, but because we have one available here, // why not use it? let key = state .key_store .signing_key_for_algorithm(&JsonWebSignatureAlg::Rs256) .unwrap(); let signer = key .params() .signing_key_for_alg(&JsonWebSignatureAlg::Rs256) .unwrap(); let header = JsonWebSignatureHeader::new(JsonWebSignatureAlg::Rs256); let id_token = Jwt::sign_with_rng(&mut rng, header, id_token_claims.clone(), &signer).unwrap(); // Provision a provider and a link let mut repo = state.repository().await.unwrap(); let provider = repo .upstream_oauth_provider() .add( &mut rng, &state.clock, UpstreamOAuthProviderParams { issuer: Some("https://example.com/".to_owned()), human_name: Some("Example Ltd.".to_owned()), brand_name: None, scope: Scope::from_iter([OPENID]), token_endpoint_auth_method: UpstreamOAuthProviderTokenAuthMethod::None, token_endpoint_signing_alg: None, id_token_signed_response_alg: JsonWebSignatureAlg::Rs256, client_id: "client".to_owned(), encrypted_client_secret: None, claims_imports, authorization_endpoint_override: None, token_endpoint_override: None, userinfo_endpoint_override: None, fetch_userinfo: false, userinfo_signed_response_alg: None, jwks_uri_override: None, discovery_mode: mas_data_model::UpstreamOAuthProviderDiscoveryMode::Oidc, pkce_mode: mas_data_model::UpstreamOAuthProviderPkceMode::Auto, response_mode: None, additional_authorization_parameters: Vec::new(), forward_login_hint: false, ui_order: 0, on_backchannel_logout: mas_data_model::UpstreamOAuthProviderOnBackchannelLogout::DoNothing, registration_token_required: false, }, ) .await .unwrap(); let session = repo .upstream_oauth_session() .add( &mut rng, &state.clock, &provider, "state".to_owned(), None, None, ) .await .unwrap(); let link = repo .upstream_oauth_link() .add( &mut rng, &state.clock, &provider, "subject".to_owned(), None, ) .await .unwrap(); let session = repo .upstream_oauth_session() .complete_with_link( &state.clock, session, &link, Some(id_token.into_string()), Some(id_token_claims), None, None, ) .await .unwrap(); repo.save().await.unwrap(); let cookie_jar = state.cookie_jar(); let upstream_sessions = UpstreamSessionsCookie::default() .add(session.id, provider.id, "state".to_owned(), None) .add_link_to_session(session.id, link.id) .unwrap(); ``` -------------------------------- ### str::as_ptr example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/struct.UserAgent.html?search= Gets a raw pointer to the first byte of a string slice. ```rust let s = "Hello"; let ptr = s.as_ptr(); ``` -------------------------------- ### Testing Compatibility Access Token Lifecycle Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_storage_pg/compat/mod.rs.html?search= Demonstrates creating a user, starting a compatibility session, adding access tokens, handling conflicts, and verifying token expiration. ```rust let mut repo = PgRepository::from_pool(&pool).await.unwrap().boxed(); // Create a user let user = repo .user() .add(&mut rng, &clock, "john".to_owned()) .await .unwrap(); // Start a compat session for that user let device = Device::generate(&mut rng); let session = repo .compat_session() .add(&mut rng, &clock, &user, device, None, false, None) .await .unwrap(); // Add an access token to that session let token = repo .compat_access_token() .add( &mut rng, &clock, &session, FIRST_TOKEN.to_owned(), Some(Duration::try_minutes(1).unwrap()), ) .await .unwrap(); assert_eq!(token.session_id, session.id); assert_eq!(token.token, FIRST_TOKEN); // Commit the txn and grab a new transaction, to test a conflict repo.save().await.unwrap(); { let mut repo = PgRepository::from_pool(&pool).await.unwrap().boxed(); // Adding the same token a second time should conflict assert!( repo.compat_access_token() .add( &mut rng, &clock, &session, FIRST_TOKEN.to_owned(), Some(Duration::try_minutes(1).unwrap()), ) .await .is_err() ); repo.cancel().await.unwrap(); } // Grab a new repo let mut repo = PgRepository::from_pool(&pool).await.unwrap().boxed(); // Looking up via ID works let token_lookup = repo .compat_access_token() .lookup(token.id) .await .unwrap() .expect("compat access token not found"); assert_eq!(token.id, token_lookup.id); assert_eq!(token_lookup.session_id, session.id); // Looking up via the token value works let token_lookup = repo .compat_access_token() .find_by_token(FIRST_TOKEN) .await .unwrap() .expect("compat access token not found"); assert_eq!(token.id, token_lookup.id); assert_eq!(token_lookup.session_id, session.id); // Token is currently valid assert!(token.is_valid(clock.now())); clock.advance(Duration::try_minutes(1).unwrap()); // Token should have expired assert!(!token.is_valid(clock.now())); // Add a second access token, this time without expiration let token = repo .compat_access_token() .add(&mut rng, &clock, &session, SECOND_TOKEN.to_owned(), None) .await .unwrap(); assert_eq!(token.session_id, session.id); assert_eq!(token.token, SECOND_TOKEN); // Token is currently valid assert!(token.is_valid(clock.now())); // Make it expire repo.compat_access_token() .expire(&clock, token) .await .unwrap(); // Reload it let token = repo .compat_access_token() .find_by_token(SECOND_TOKEN) .await .unwrap() .expect("compat access token not found"); // Token is not valid anymore assert!(!token.is_valid(clock.now())); repo.save().await.unwrap(); ``` -------------------------------- ### timestamp_micros() example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_jose/claims/struct.Timestamp.html Shows how to get the number of microseconds since the Unix epoch for two different DateTime values. ```rust use chrono::{NaiveDate, Utc}; let dt = NaiveDate::from_ymd_opt(1970, 1, 1) .unwrap() .and_hms_micro_opt(0, 0, 1, 444) .unwrap() .and_local_timezone(Utc) .unwrap(); assert_eq!(dt.timestamp_micros(), 1_000_444); let dt = NaiveDate::from_ymd_opt(2001, 9, 9) .unwrap() .and_hms_micro_opt(1, 46, 40, 555) .unwrap() .and_local_timezone(Utc) .unwrap(); assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555); ``` -------------------------------- ### Example Migration Checksum Output Source: https://element-hq.github.io/matrix-authentication-service/development/database.html Sample output from the checksum query, showing the migration version and its short checksum. ```text version | short_checksum ----------------+---------------------------------- 20250410000002 | f2b8f120deae27e760d079a30b77eea3 ``` -------------------------------- ### Setup Schedules Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_tasks/new_queue.rs.html Initializes queue schedules in the database within a transaction. ```rust #[tracing::instrument(name = "worker.setup_schedules", skip_all)] pub(crate) async fn setup_schedules(&mut self) -> Result<(), QueueRunnerError> { let schedules: Vec<_> = self.schedules.iter().map(|s| s.schedule_name).collect(); // Start a transaction on the existing PgListener connection let txn = self .listener .begin() .await .map_err(QueueRunnerError::StartTransaction)?; let mut repo = PgRepository::from_conn(txn); // Setup the entries in the queue_schedules table repo.queue_schedule().setup(&schedules).await?; repo.into_inner() .commit() .await .map_err(QueueRunnerError::CommitTransaction)?; Ok(()) } ``` -------------------------------- ### timestamp_millis() example Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_jose/claims/struct.Timestamp.html Shows how to get the number of milliseconds since the Unix epoch for two different DateTime values. ```rust use chrono::{NaiveDate, Utc}; let dt = NaiveDate::from_ymd_opt(1970, 1, 1) .unwrap() .and_hms_milli_opt(0, 0, 1, 444) .unwrap() .and_local_timezone(Utc) .unwrap(); assert_eq!(dt.timestamp_millis(), 1_444); let dt = NaiveDate::from_ymd_opt(2001, 9, 9) .unwrap() .and_hms_milli_opt(1, 46, 40, 555) .unwrap() .and_local_timezone(Utc) .unwrap(); assert_eq!(dt.timestamp_millis(), 1_000_000_000_555); ``` -------------------------------- ### Setup user session list test Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/admin/v1/user_sessions/list.rs.html?search= Initializes the test state and creates a user and session for testing. ```rust #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] async fn test_user_session_list_by_last_active(pool: PgPool) { setup(); let mut state = TestState::from_pool(pool).await.unwrap(); let token = state.token_with_scope("urn:mas:admin").await; let mut rng = state.rng(); let mut repo = state.repository().await.unwrap(); let user = repo .user() .add(&mut rng, &state.clock, "alice".to_owned()) .await .unwrap(); let session = repo .browser_session() .add(&mut rng, &state.clock, &user, None) .await .unwrap(); ``` -------------------------------- ### Example response for GET /api/admin/v1/upstream-oauth-links/{id} Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_handlers/admin/v1/upstream_oauth_links/get.rs.html Shows the JSON structure returned when the link is found, including attributes and links. ```json { "id": "01FSHN9AG09NMZYX8MFYH578R9", "attributes": { "created_at": "2022-01-16T14:40:00Z", "provider_id": "01FSHN9AG0MZAA6S4AF7CTV32E", "subject": "subject1", "user_id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4", "human_account_name": null }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG09NMZYX8MFYH578R9" } } ``` -------------------------------- ### iter.next() Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_keystore/struct.Keystore.html Returns the next range in the iteration. The example shows successive calls returning ranges with start and end indices. ```APIDOC ## iter.next() ### Description Returns the next range in the iteration. The example shows successive calls returning ranges with start and end indices. ### Method next ### Parameters None ### Return Value Option - The next range, or None if iteration is complete. ### Example ```rust assert_eq!(iter.next(), Some(Range { start: 0, end: 0 })); assert_eq!(iter.next(), Some(Range { start: 1, end: 3 })); assert_eq!(iter.next(), Some(Range { start: 4, end: 4 })); assert_eq!(iter.next(), Some(Range { start: 5, end: 6 })); ``` ``` -------------------------------- ### Logging with tracing macros Source: https://element-hq.github.io/matrix-authentication-service/development/architecture.html Example using tracing::info and debug! to log messages, including structured fields. Requires installing a subscriber (e.g., tracing-subscriber) to output logs; the CLI installs one at startup and reads RUST_LOG for filtering. ```rust #![allow(unused)] fn main() { use tracing::{info, debug}; info!("Logging some things"); debug!(user = "john", "Structured stuff"); } ``` -------------------------------- ### Manually create Box from scratch using global allocator Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/mas_data_model/type.BoxRng.html Example for `Box::from_raw` that manually allocates memory and writes a value before constructing the `Box`. ```rust use std::alloc::{alloc, Layout}; unsafe { let ptr = alloc(Layout::new::()) as *mut i32; // In general .write is required to avoid attempting to destruct // the (uninitialized) previous contents of `ptr`, though for this // simple example `*ptr = 5` would have worked as well. ptr.write(5); let x = Box::from_raw(ptr); } ``` -------------------------------- ### Access Token Repository Test Setup Source: https://element-hq.github.io/matrix-authentication-service/rustdoc/src/mas_storage_pg/compat/mod.rs.html Initializes the test environment for the access token repository. ```rust #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_access_token_repository(pool: PgPool) { const FIRST_TOKEN: &str = "first_access_token"; const SECOND_TOKEN: &str = "second_access_token"; let mut rng = ChaChaRng::seed_from_u64(42); let clock = MockClock::default(); ```