add: user requests in js app sdk
This commit is contained in:
parent
884a89904e
commit
0138bf4cd4
52 changed files with 282 additions and 53 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3276,6 +3276,7 @@ dependencies = [
|
||||||
"axum-extra",
|
"axum-extra",
|
||||||
"cf-turnstile",
|
"cf-turnstile",
|
||||||
"contrasted",
|
"contrasted",
|
||||||
|
"cookie",
|
||||||
"emojis",
|
"emojis",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"image",
|
"image",
|
||||||
|
|
|
@ -22,7 +22,6 @@ ammonia = "4.1.1"
|
||||||
tetratto-shared = { path = "../shared" }
|
tetratto-shared = { path = "../shared" }
|
||||||
tetratto-core = { path = "../core" }
|
tetratto-core = { path = "../core" }
|
||||||
tetratto-l10n = { path = "../l10n" }
|
tetratto-l10n = { path = "../l10n" }
|
||||||
|
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
reqwest = { version = "0.12.22", features = ["json", "stream"] }
|
reqwest = { version = "0.12.22", features = ["json", "stream"] }
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
|
@ -42,3 +41,4 @@ async-stripe = { version = "0.41.0", features = [
|
||||||
emojis = "0.7.0"
|
emojis = "0.7.0"
|
||||||
webp = "0.3.0"
|
webp = "0.3.0"
|
||||||
nanoneo = "0.2.0"
|
nanoneo = "0.2.0"
|
||||||
|
cookie = "0.18.1"
|
||||||
|
|
68
crates/app/src/cookie.rs
Normal file
68
crates/app/src/cookie.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use std::convert::Infallible;
|
||||||
|
use axum::{
|
||||||
|
extract::FromRequestParts,
|
||||||
|
http::{request::Parts, HeaderMap},
|
||||||
|
};
|
||||||
|
use cookie::{Cookie, CookieJar as CookieCookieJar};
|
||||||
|
|
||||||
|
/// This is required because "Cookie" his a forbidden header for some fucking reason.
|
||||||
|
/// Stupidest thing I've ever encountered in JavaScript, absolute fucking insanity.
|
||||||
|
///
|
||||||
|
/// Anyway, most of this shit is just from the original source for axum_extra::extract::CookieJar,
|
||||||
|
/// just edited to use X-Cookie instead.
|
||||||
|
///
|
||||||
|
/// Stuff from axum_extra will have links to the original provided.
|
||||||
|
pub struct CookieJar {
|
||||||
|
jar: CookieCookieJar,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://docs.rs/axum-extra/latest/src/axum_extra/extract/cookie/mod.rs.html#92-101>
|
||||||
|
impl<S> FromRequestParts<S> for CookieJar
|
||||||
|
where
|
||||||
|
S: Send + Sync,
|
||||||
|
{
|
||||||
|
type Rejection = Infallible;
|
||||||
|
|
||||||
|
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||||
|
Ok(Self::from_headers(&parts.headers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cookies_from_request(
|
||||||
|
header: String,
|
||||||
|
headers: &HeaderMap,
|
||||||
|
) -> impl Iterator<Item = Cookie<'static>> + '_ {
|
||||||
|
headers
|
||||||
|
.get_all(header)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|value| value.to_str().ok())
|
||||||
|
.flat_map(|value| value.split(';'))
|
||||||
|
.filter_map(|cookie| Cookie::parse_encoded(cookie.to_owned()).ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CookieJar {
|
||||||
|
/// <https://docs.rs/axum-extra/latest/axum_extra/extract/cookie/struct.CookieJar.html#method.from_headers>
|
||||||
|
///
|
||||||
|
/// Modified only to prefer "X-Cookie" header.
|
||||||
|
pub fn from_headers(headers: &HeaderMap) -> Self {
|
||||||
|
let mut jar = CookieCookieJar::new();
|
||||||
|
|
||||||
|
for cookie in cookies_from_request(
|
||||||
|
if headers.contains_key("X-Cookie") {
|
||||||
|
"X-Cookie".to_string()
|
||||||
|
} else {
|
||||||
|
"Cookie".to_string()
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
) {
|
||||||
|
jar.add_original(cookie.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { jar }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://docs.rs/axum-extra/latest/axum_extra/extract/cookie/struct.CookieJar.html#method.get>
|
||||||
|
pub fn get(&self, name: &str) -> Option<&Cookie<'static>> {
|
||||||
|
self.jar.get(name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#![doc(html_favicon_url = "/public/favicon.svg")]
|
#![doc(html_favicon_url = "/public/favicon.svg")]
|
||||||
#![doc(html_logo_url = "/public/tetratto_bunny.webp")]
|
#![doc(html_logo_url = "/public/tetratto_bunny.webp")]
|
||||||
mod assets;
|
mod assets;
|
||||||
|
mod cookie;
|
||||||
mod image;
|
mod image;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
const search = new URLSearchParams(window.location.search);
|
const search = new URLSearchParams(window.location.search);
|
||||||
search.append(\"verifier\", verifier);
|
search.append(\"verifier\", verifier);
|
||||||
search.append(\"token\", res.payload);
|
search.append(\"token\", res.payload);
|
||||||
|
search.append(\"uid\", \"{{ user.id }}\");
|
||||||
|
|
||||||
window.location.href = `{{ app.redirect|remove_script_tags|safe }}?${search.toString()}`;
|
window.location.href = `{{ app.redirect|remove_script_tags|safe }}?${search.toString()}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,45 @@ import {
|
||||||
JSONStringify as json_stringify,
|
JSONStringify as json_stringify,
|
||||||
} from "https://unpkg.com/json-with-bigint@3.4.4/json-with-bigint.js";
|
} from "https://unpkg.com/json-with-bigint@3.4.4/json-with-bigint.js";
|
||||||
|
|
||||||
export default function tetratto(tetratto_host, api_key) {
|
/// PKCE key generation.
|
||||||
|
export const PKCE = {
|
||||||
|
/// Create a verifier for [`PKCE::challenge`].
|
||||||
|
verifier: async (length) => {
|
||||||
|
let text = "";
|
||||||
|
const possible =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
text += possible.charAt(
|
||||||
|
Math.floor(Math.random() * possible.length),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
/// Create the challenge needed to request a user token.
|
||||||
|
challenge: async (verifier) => {
|
||||||
|
const data = new TextEncoder().encode(verifier);
|
||||||
|
const digest = await window.crypto.subtle.digest("SHA-256", data);
|
||||||
|
return btoa(
|
||||||
|
String.fromCharCode.apply(null, [...new Uint8Array(digest)]),
|
||||||
|
)
|
||||||
|
.replace(/\+/g, "-")
|
||||||
|
.replace(/\//g, "_")
|
||||||
|
.replace(/=+$/, "");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function tetratto({
|
||||||
|
host = "https://tetratto.com",
|
||||||
|
api_key = null,
|
||||||
|
app_id = 0n,
|
||||||
|
user_token = null,
|
||||||
|
user_verifier = null,
|
||||||
|
user_id = 0n,
|
||||||
|
}) {
|
||||||
|
const GRANT_URL = `${host}/auth/connections_link/app/${app_id}`;
|
||||||
|
|
||||||
function api_promise(res) {
|
function api_promise(res) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
|
@ -14,11 +52,16 @@ export default function tetratto(tetratto_host, api_key) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// app data
|
||||||
async function app() {
|
async function app() {
|
||||||
|
if (!api_key) {
|
||||||
|
throw Error("No API key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
return api_promise(
|
return api_promise(
|
||||||
json_parse(
|
json_parse(
|
||||||
await (
|
await (
|
||||||
await fetch(`${tetratto_host}/api/v1/app_data/app`, {
|
await fetch(`${host}/api/v1/app_data/app`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Atto-Secret-Key": api_key,
|
"Atto-Secret-Key": api_key,
|
||||||
|
@ -30,10 +73,14 @@ export default function tetratto(tetratto_host, api_key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function query(body) {
|
async function query(body) {
|
||||||
|
if (!api_key) {
|
||||||
|
throw Error("No API key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
return api_promise(
|
return api_promise(
|
||||||
json_parse(
|
json_parse(
|
||||||
await (
|
await (
|
||||||
await fetch(`${tetratto_host}/api/v1/app_data/query`, {
|
await fetch(`${host}/api/v1/app_data/query`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
@ -47,10 +94,14 @@ export default function tetratto(tetratto_host, api_key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insert(key, value) {
|
async function insert(key, value) {
|
||||||
|
if (!api_key) {
|
||||||
|
throw Error("No API key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
return api_promise(
|
return api_promise(
|
||||||
json_parse(
|
json_parse(
|
||||||
await (
|
await (
|
||||||
await fetch(`${tetratto_host}/api/v1/app_data`, {
|
await fetch(`${host}/api/v1/app_data`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
@ -67,10 +118,14 @@ export default function tetratto(tetratto_host, api_key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remove(id) {
|
async function remove(id) {
|
||||||
|
if (!api_key) {
|
||||||
|
throw Error("No API key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
return api_promise(
|
return api_promise(
|
||||||
json_parse(
|
json_parse(
|
||||||
await (
|
await (
|
||||||
await fetch(`${tetratto_host}/api/v1/app_data/${id}`, {
|
await fetch(`${host}/api/v1/app_data/${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Atto-Secret-Key": api_key,
|
"Atto-Secret-Key": api_key,
|
||||||
|
@ -82,10 +137,14 @@ export default function tetratto(tetratto_host, api_key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remove_query(body) {
|
async function remove_query(body) {
|
||||||
|
if (!api_key) {
|
||||||
|
throw Error("No API key provided.");
|
||||||
|
}
|
||||||
|
|
||||||
return api_promise(
|
return api_promise(
|
||||||
json_parse(
|
json_parse(
|
||||||
await (
|
await (
|
||||||
await fetch(`${tetratto_host}/api/v1/app_data/query`, {
|
await fetch(`${host}/api/v1/app_data/query`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
@ -98,11 +157,110 @@ export default function tetratto(tetratto_host, api_key) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user connection
|
||||||
|
/// Extract the verifier, token, and user ID from the URL.
|
||||||
|
function extract_verifier_token_uid() {
|
||||||
|
const search = new URLSearchParams(window.location.search);
|
||||||
|
return [
|
||||||
|
search.get("verifier"),
|
||||||
|
search.get("token"),
|
||||||
|
BigInt(search.get("uid")),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accept a connection grant and store it in localStorage.
|
||||||
|
function localstorage_accept_connection() {
|
||||||
|
const [verifier, token, uid] = extract_verifier_token_uid();
|
||||||
|
window.localStorage.setItem("atto:grant.verifier", verifier);
|
||||||
|
window.localStorage.setItem("atto:grant.token", token);
|
||||||
|
window.localStorage.setItem("atto:grant.user_id", uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refresh_token(verifier) {
|
||||||
|
if (!user_token) {
|
||||||
|
throw Error("No user token provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_promise(
|
||||||
|
json_parse(
|
||||||
|
await (
|
||||||
|
await fetch(
|
||||||
|
`${host}/api/v1/auth/user/${user_id}/grants/${app_id}/refresh`,
|
||||||
|
{
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Cookie": `__Secure-atto-token=${user_token}`,
|
||||||
|
},
|
||||||
|
body: json_stringify({
|
||||||
|
verifier,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
).text(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function request({
|
||||||
|
api_path,
|
||||||
|
method = "POST",
|
||||||
|
content_type = "application/json",
|
||||||
|
body = "{}",
|
||||||
|
}) {
|
||||||
|
if (!user_token) {
|
||||||
|
throw Error("No user token provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_promise(
|
||||||
|
json_parse(
|
||||||
|
await (
|
||||||
|
await fetch(`${host}/api/v1/${api_path}`, {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": content_type,
|
||||||
|
"X-Cookie": `__Secure-atto-token=${user_token}`,
|
||||||
|
},
|
||||||
|
body:
|
||||||
|
content_type === "application/json"
|
||||||
|
? json_stringify(body)
|
||||||
|
: body,
|
||||||
|
})
|
||||||
|
).text(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
return {
|
return {
|
||||||
|
// app data
|
||||||
app,
|
app,
|
||||||
query,
|
query,
|
||||||
insert,
|
insert,
|
||||||
remove,
|
remove,
|
||||||
remove_query,
|
remove_query,
|
||||||
|
// user connection
|
||||||
|
GRANT_URL,
|
||||||
|
extract_verifier_token_uid,
|
||||||
|
refresh_token,
|
||||||
|
localstorage_accept_connection,
|
||||||
|
request,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function from_localstorage({
|
||||||
|
host = "https://tetratto.com",
|
||||||
|
app_id = 0n,
|
||||||
|
}) {
|
||||||
|
const user_verifier = window.localStorage.getItem("atto:grant.verifier");
|
||||||
|
const user_token = window.localStorage.getItem("atto:grant.token");
|
||||||
|
const user_id = window.localStorage.getItem("atto:grant.user_id");
|
||||||
|
|
||||||
|
return tetratto({
|
||||||
|
host,
|
||||||
|
app_id,
|
||||||
|
user_verifier,
|
||||||
|
user_id,
|
||||||
|
user_token,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
State,
|
State,
|
||||||
};
|
};
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
apps::{AppQuota, ThirdPartyApp},
|
apps::{AppQuota, ThirdPartyApp},
|
||||||
oauth::{AuthGrant, PkceChallengeMethod},
|
oauth::{AuthGrant, PkceChallengeMethod},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use axum::{extract::Path, response::IntoResponse, Extension, Json};
|
use axum::{extract::Path, response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
database::connections::last_fm::LastFmConnection,
|
database::connections::last_fm::LastFmConnection,
|
||||||
model::{
|
model::{
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub mod stripe;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use axum::{extract::Path, response::IntoResponse, Extension, Json};
|
use axum::{extract::Path, response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
auth::{ConnectionService, ExternalConnectionData},
|
auth::{ConnectionService, ExternalConnectionData},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use axum::{response::IntoResponse, Extension, Json};
|
use axum::{response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
database::connections::spotify::SpotifyConnection,
|
database::connections::spotify::SpotifyConnection,
|
||||||
model::{
|
model::{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{str::FromStr, time::Duration};
|
use std::{str::FromStr, time::Duration};
|
||||||
|
|
||||||
use axum::{http::HeaderMap, response::IntoResponse, Extension, Json};
|
use axum::{http::HeaderMap, response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
auth::{Notification, User},
|
auth::{Notification, User},
|
||||||
moderation::AuditLogEntry,
|
moderation::AuditLogEntry,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
extract::{Path, Query},
|
extract::{Path, Query},
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use pathbufd::{PathBufD, pathd};
|
use pathbufd::{PathBufD, pathd};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
routes::api::v1::CreateIpBan,
|
routes::api::v1::CreateIpBan,
|
||||||
};
|
};
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{addr::RemoteAddr, auth::IpBan, permissions::FinePermission};
|
use tetratto_core::model::{addr::RemoteAddr, auth::IpBan, permissions::FinePermission};
|
||||||
|
|
||||||
/// Create a new IP ban.
|
/// Create a new IP ban.
|
||||||
|
|
|
@ -16,7 +16,7 @@ use axum::{
|
||||||
response::{IntoResponse, Redirect},
|
response::{IntoResponse, Redirect},
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::model::addr::RemoteAddr;
|
use tetratto_core::model::addr::RemoteAddr;
|
||||||
use tetratto_shared::hash::hash;
|
use tetratto_shared::hash::hash;
|
||||||
|
|
|
@ -18,7 +18,7 @@ use axum::{
|
||||||
response::{IntoResponse, Redirect},
|
response::{IntoResponse, Redirect},
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use futures_util::{sink::SinkExt, stream::StreamExt};
|
use futures_util::{sink::SinkExt, stream::StreamExt};
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
cache::Cache,
|
cache::Cache,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
addr::RemoteAddr,
|
addr::RemoteAddr,
|
||||||
auth::{AchievementName, FollowResult, IpBlock, Notification, UserBlock, UserFollow},
|
auth::{AchievementName, FollowResult, IpBlock, Notification, UserBlock, UserFollow},
|
||||||
|
|
|
@ -9,7 +9,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{auth::UserWarning, oauth, permissions::FinePermission};
|
use tetratto_core::model::{auth::UserWarning, oauth, permissions::FinePermission};
|
||||||
|
|
||||||
/// Create a new user warning.
|
/// Create a new user warning.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{oauth, channels::Channel, ApiReturn, Error};
|
use tetratto_core::model::{oauth, channels::Channel, ApiReturn, Error};
|
||||||
use crate::{
|
use crate::{
|
||||||
get_user_from_token,
|
get_user_from_token,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{get_user_from_token, routes::api::v1::CreateMessageReaction, State};
|
use crate::{get_user_from_token, routes::api::v1::CreateMessageReaction, State};
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{channels::MessageReaction, oauth, ApiReturn, Error};
|
use tetratto_core::model::{channels::MessageReaction, oauth, ApiReturn, Error};
|
||||||
|
|
||||||
pub async fn get_request(
|
pub async fn get_request(
|
||||||
|
|
|
@ -7,7 +7,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
cache::{Cache, redis::Commands},
|
cache::{Cache, redis::Commands},
|
||||||
model::{
|
model::{
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
extract::Path,
|
extract::Path,
|
||||||
response::{IntoResponse, Redirect},
|
response::{IntoResponse, Redirect},
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
auth::Notification,
|
auth::Notification,
|
||||||
communities::{Community, CommunityMembership},
|
communities::{Community, CommunityMembership},
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{auth::AchievementName, communities::PostDraft, oauth, ApiReturn, Error};
|
use tetratto_core::model::{auth::AchievementName, communities::PostDraft, oauth, ApiReturn, Error};
|
||||||
use crate::{
|
use crate::{
|
||||||
get_user_from_token,
|
get_user_from_token,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
State,
|
State,
|
||||||
};
|
};
|
||||||
use axum::{body::Body, extract::Path, response::IntoResponse, Extension, Json};
|
use axum::{body::Body, extract::Path, response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
oauth,
|
oauth,
|
||||||
uploads::{CustomEmoji, MediaType, MediaUpload},
|
uploads::{CustomEmoji, MediaType, MediaUpload},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use axum::{Extension, Json, body::Body, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, body::Body, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use pathbufd::{PathBufD, pathd};
|
use pathbufd::{PathBufD, pathd};
|
||||||
use std::fs::exists;
|
use std::fs::exists;
|
||||||
use tetratto_core::model::{ApiReturn, Error, permissions::FinePermission, oauth};
|
use tetratto_core::model::{ApiReturn, Error, permissions::FinePermission, oauth};
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
addr::RemoteAddr,
|
addr::RemoteAddr,
|
||||||
auth::AchievementName,
|
auth::AchievementName,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
addr::RemoteAddr,
|
addr::RemoteAddr,
|
||||||
auth::{AchievementName, IpBlock},
|
auth::{AchievementName, IpBlock},
|
||||||
|
|
|
@ -9,7 +9,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
auth::AchievementName,
|
auth::AchievementName,
|
||||||
littleweb::{Domain, ServiceFsMime},
|
littleweb::{Domain, ServiceFsMime},
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
extract::{Json, Path},
|
extract::{Json, Path},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_shared::snow::Snowflake;
|
use tetratto_shared::snow::Snowflake;
|
||||||
use crate::{
|
use crate::{
|
||||||
get_user_from_token,
|
get_user_from_token,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
extract::{Json, Path},
|
extract::{Json, Path},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_shared::unix_epoch_timestamp;
|
use tetratto_shared::unix_epoch_timestamp;
|
||||||
use crate::{
|
use crate::{
|
||||||
get_user_from_token,
|
get_user_from_token,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{oauth, ApiReturn, Error};
|
use tetratto_core::model::{oauth, ApiReturn, Error};
|
||||||
|
|
||||||
pub async fn delete_request(
|
pub async fn delete_request(
|
||||||
|
|
|
@ -15,7 +15,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
oauth,
|
oauth,
|
||||||
products::Product,
|
products::Product,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{addr::RemoteAddr, oauth, reactions::Reaction, ApiReturn, Error};
|
use tetratto_core::model::{addr::RemoteAddr, oauth, reactions::Reaction, ApiReturn, Error};
|
||||||
|
|
||||||
pub async fn get_request(
|
pub async fn get_request(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::CreateReport;
|
use super::CreateReport;
|
||||||
use crate::{State, get_user_from_token};
|
use crate::{State, get_user_from_token};
|
||||||
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
use axum::{Extension, Json, extract::Path, response::IntoResponse};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{ApiReturn, Error, moderation::Report};
|
use tetratto_core::model::{ApiReturn, Error, moderation::Report};
|
||||||
|
|
||||||
pub async fn create_request(
|
pub async fn create_request(
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{oauth, ApiReturn, Error};
|
use tetratto_core::model::{oauth, ApiReturn, Error};
|
||||||
|
|
||||||
pub async fn delete_request(
|
pub async fn delete_request(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
State,
|
State,
|
||||||
};
|
};
|
||||||
use axum::{extract::Path, response::IntoResponse, Extension, Json};
|
use axum::{extract::Path, response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{auth::AchievementName, littleweb::Service, oauth, ApiReturn, Error};
|
use tetratto_core::model::{auth::AchievementName, littleweb::Service, oauth, ApiReturn, Error};
|
||||||
use tetratto_shared::unix_epoch_timestamp;
|
use tetratto_shared::unix_epoch_timestamp;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
model::{
|
model::{
|
||||||
oauth,
|
oauth,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fs::exists;
|
use std::fs::exists;
|
||||||
use axum::{body::Body, extract::Path, response::IntoResponse, Extension, Json};
|
use axum::{body::Body, extract::Path, response::IntoResponse, Extension, Json};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use pathbufd::PathBufD;
|
use pathbufd::PathBufD;
|
||||||
use crate::{get_user_from_token, routes::api::v1::UpdateUploadAlt, State};
|
use crate::{get_user_from_token, routes::api::v1::UpdateUploadAlt, State};
|
||||||
use super::auth::images::read_image;
|
use super::auth::images::read_image;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use pathbufd::PathBufD;
|
use pathbufd::PathBufD;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::model::permissions::FinePermission;
|
use tetratto_core::model::permissions::FinePermission;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{Error, auth::ConnectionService};
|
use tetratto_core::model::{Error, auth::ConnectionService};
|
||||||
|
|
||||||
use super::render_error;
|
use super::render_error;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse, Redirect},
|
response::{Html, IntoResponse, Redirect},
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
channels::Message, communities_permissions::CommunityPermission, permissions::FinePermission,
|
channels::Message, communities_permissions::CommunityPermission, permissions::FinePermission,
|
||||||
Error,
|
Error,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
extract::Path,
|
extract::Path,
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{apps::AppData, permissions::FinePermission, Error};
|
use tetratto_core::model::{apps::AppData, permissions::FinePermission, Error};
|
||||||
|
|
||||||
/// `/developer`
|
/// `/developer`
|
||||||
|
|
|
@ -8,7 +8,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{communities::Community, Error};
|
use tetratto_core::model::{communities::Community, Error};
|
||||||
|
|
||||||
/// `/forges`
|
/// `/forges`
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse, Redirect},
|
response::{Html, IntoResponse, Redirect},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::initial_context,
|
assets::initial_context,
|
||||||
check_user_blocked_or_private, get_lang, get_user_from_token,
|
check_user_blocked_or_private, get_lang, get_user_from_token,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use axum::{
|
||||||
extract::{Query, Path},
|
extract::{Query, Path},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{littleweb::TLDS_VEC, permissions::SecondaryPermission, Error};
|
use tetratto_core::model::{littleweb::TLDS_VEC, permissions::SecondaryPermission, Error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_shared::hash::salt;
|
use tetratto_shared::hash::salt;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::Error;
|
use tetratto_core::model::Error;
|
||||||
|
|
||||||
/// `/settings/seller`
|
/// `/settings/seller`
|
||||||
|
|
|
@ -7,7 +7,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
auth::{AchievementName, DefaultTimelineChoice, ACHIEVEMENTS},
|
auth::{AchievementName, DefaultTimelineChoice, ACHIEVEMENTS},
|
||||||
|
|
|
@ -15,7 +15,7 @@ use axum::{
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
model::{Error, auth::User},
|
model::{Error, auth::User},
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::{
|
use tetratto_core::{
|
||||||
cache::Cache,
|
cache::Cache,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use axum::{
|
||||||
extract::{Path, Query},
|
extract::{Path, Query},
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
|
|
|
@ -3,7 +3,7 @@ use axum::{
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use crate::cookie::CookieJar;
|
||||||
use tetratto_core::model::{
|
use tetratto_core::model::{
|
||||||
auth::User,
|
auth::User,
|
||||||
permissions::FinePermission,
|
permissions::FinePermission,
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub struct ThirdPartyApp {
|
||||||
/// if the verifier doesn't match, it won't pass the challenge.
|
/// if the verifier doesn't match, it won't pass the challenge.
|
||||||
///
|
///
|
||||||
/// Requests to API endpoints using your grant token should be sent with a
|
/// Requests to API endpoints using your grant token should be sent with a
|
||||||
/// cookie (in the `Cookie` header) named `Atto-Grant`. This cookie should
|
/// cookie (in the `Cookie` or `X-Cookie` header) named `Atto-Grant`. This cookie should
|
||||||
/// contain the token you received from either the initial connection,
|
/// contain the token you received from either the initial connection,
|
||||||
/// or a token refresh.
|
/// or a token refresh.
|
||||||
pub redirect: String,
|
pub redirect: String,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue