Merge branch 'develop' into iceshrimp_mastodon

This commit is contained in:
naskya 2024-06-05 12:33:48 +09:00
commit be894399a5
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
54 changed files with 107 additions and 101 deletions

View file

@ -433,7 +433,8 @@ export function isQuote(note: NoteLikeForIsQuote): boolean
export function isSafeUrl(url: string): boolean export function isSafeUrl(url: string): boolean
/** Returns the latest Firefish version. */ /** Returns the latest Firefish version. */
export function latestVersion(): Promise<string> export function latestVersion(): Promise<string>
export function fetchMeta(useCache: boolean): Promise<Meta> export function fetchMeta(): Promise<Meta>
export function updateMetaCache(): Promise<void>
export interface PugArgs { export interface PugArgs {
img: string | null img: string | null
title: string title: string

View file

@ -310,7 +310,7 @@ if (!nativeBinding) {
throw new Error(`Failed to load native binding`) throw new Error(`Failed to load native binding`)
} }
const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, sqlRegexEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isQuote, isSafeUrl, latestVersion, fetchMeta, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, PushSubscriptionType, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding const { SECOND, MINUTE, HOUR, DAY, USER_ONLINE_THRESHOLD, USER_ACTIVE_THRESHOLD, FILE_TYPE_BROWSERSAFE, loadEnv, loadConfig, stringToAcct, acctToString, fetchNodeinfo, nodeinfo_2_1, nodeinfo_2_0, Protocol, Inbound, Outbound, greet, initializeRustLogger, showServerInfo, isBlockedServer, isSilencedServer, isAllowedServer, checkWordMute, getFullApAccount, isSelfHost, isSameOrigin, extractHost, toPuny, isUnicodeEmoji, sqlLikeEscape, sqlRegexEscape, safeForSql, formatMilliseconds, getImageSizeFromUrl, getNoteSummary, isQuote, isSafeUrl, latestVersion, fetchMeta, updateMetaCache, metaToPugArgs, nyaify, hashPassword, verifyPassword, isOldPasswordAlgorithm, decodeReaction, countReactions, toDbReaction, removeOldAttestationChallenges, cpuInfo, cpuUsage, memoryUsage, storageUsage, AntennaSrc, DriveFileUsageHint, MutedNoteReason, NoteVisibility, NotificationType, PageVisibility, PollNoteVisibility, PushSubscriptionType, RelayStatus, UserEmojiModPerm, UserProfileFfvisibility, UserProfileMutingNotificationTypes, updateAntennasOnNewNote, watchNote, unwatchNote, PushNotificationKind, sendPushNotification, publishToChannelStream, ChatEvent, publishToChatStream, ChatIndexEvent, publishToChatIndexStream, publishToBroadcastStream, publishToGroupChatStream, publishToModerationStream, getTimestamp, genId, genIdAt, generateSecureRandomString, generateUserToken } = nativeBinding
module.exports.SECOND = SECOND module.exports.SECOND = SECOND
module.exports.MINUTE = MINUTE module.exports.MINUTE = MINUTE
@ -352,6 +352,7 @@ module.exports.isQuote = isQuote
module.exports.isSafeUrl = isSafeUrl module.exports.isSafeUrl = isSafeUrl
module.exports.latestVersion = latestVersion module.exports.latestVersion = latestVersion
module.exports.fetchMeta = fetchMeta module.exports.fetchMeta = fetchMeta
module.exports.updateMetaCache = updateMetaCache
module.exports.metaToPugArgs = metaToPugArgs module.exports.metaToPugArgs = metaToPugArgs
module.exports.nyaify = nyaify module.exports.nyaify = nyaify
module.exports.hashPassword = hashPassword module.exports.hashPassword = hashPassword

View file

@ -23,10 +23,8 @@ pub enum Error {
Redis(#[from] RedisError), Redis(#[from] RedisError),
#[error("Redis connection error: {0}")] #[error("Redis connection error: {0}")]
RedisConn(#[from] RedisConnError), RedisConn(#[from] RedisConnError),
#[error("Data serialization error: {0}")] #[error("Failed to encode the data: {0}")]
Serialize(#[from] rmp_serde::encode::Error), Encode(#[from] rmp_serde::encode::Error),
#[error("Data deserialization error: {0}")]
Deserialize(#[from] rmp_serde::decode::Error),
} }
#[inline] #[inline]
@ -123,7 +121,7 @@ pub async fn set<V: for<'a> Deserialize<'a> + Serialize>(
pub async fn get<V: for<'a> Deserialize<'a> + Serialize>(key: &str) -> Result<Option<V>, Error> { pub async fn get<V: for<'a> Deserialize<'a> + Serialize>(key: &str) -> Result<Option<V>, Error> {
let serialized_value: Option<Vec<u8>> = redis_conn().await?.get(prefix_key(key)).await?; let serialized_value: Option<Vec<u8>> = redis_conn().await?.get(prefix_key(key)).await?;
Ok(match serialized_value { Ok(match serialized_value {
Some(v) => Some(rmp_serde::from_slice::<V>(v.as_ref())?), Some(v) => rmp_serde::from_slice::<V>(v.as_ref()).ok(),
None => None, None => None,
}) })
} }

View file

@ -63,7 +63,7 @@ async fn statistics() -> Result<(u64, u64, u64, u64), DbErr> {
async fn generate_nodeinfo_2_1() -> Result<Nodeinfo21, Error> { async fn generate_nodeinfo_2_1() -> Result<Nodeinfo21, Error> {
let (local_users, local_active_halfyear, local_active_month, local_posts) = let (local_users, local_active_halfyear, local_active_month, local_posts) =
statistics().await?; statistics().await?;
let meta = fetch_meta(true).await?; let meta = fetch_meta().await?;
let metadata = HashMap::from([ let metadata = HashMap::from([
( (
"nodeName".to_string(), "nodeName".to_string(),

View file

@ -20,7 +20,7 @@
/// ``` /// ```
#[crate::ts_export] #[crate::ts_export]
pub async fn is_blocked_server(host: &str) -> Result<bool, sea_orm::DbErr> { pub async fn is_blocked_server(host: &str) -> Result<bool, sea_orm::DbErr> {
Ok(crate::misc::meta::fetch_meta(true) Ok(crate::misc::meta::fetch_meta()
.await? .await?
.blocked_hosts .blocked_hosts
.iter() .iter()
@ -47,7 +47,7 @@ pub async fn is_blocked_server(host: &str) -> Result<bool, sea_orm::DbErr> {
/// ``` /// ```
#[crate::ts_export] #[crate::ts_export]
pub async fn is_silenced_server(host: &str) -> Result<bool, sea_orm::DbErr> { pub async fn is_silenced_server(host: &str) -> Result<bool, sea_orm::DbErr> {
Ok(crate::misc::meta::fetch_meta(true) Ok(crate::misc::meta::fetch_meta()
.await? .await?
.silenced_hosts .silenced_hosts
.iter() .iter()
@ -75,7 +75,7 @@ pub async fn is_silenced_server(host: &str) -> Result<bool, sea_orm::DbErr> {
/// ``` /// ```
#[crate::ts_export] #[crate::ts_export]
pub async fn is_allowed_server(host: &str) -> Result<bool, sea_orm::DbErr> { pub async fn is_allowed_server(host: &str) -> Result<bool, sea_orm::DbErr> {
let meta = crate::misc::meta::fetch_meta(true).await?; let meta = crate::misc::meta::fetch_meta().await?;
if !meta.private_mode.unwrap_or(false) { if !meta.private_mode.unwrap_or(false) {
return Ok(true); return Ok(true);

View file

@ -7,12 +7,22 @@ use std::sync::Mutex;
type Meta = meta::Model; type Meta = meta::Model;
static CACHE: Mutex<Option<Meta>> = Mutex::new(None); static CACHE: Mutex<Option<Meta>> = Mutex::new(None);
fn update_cache(meta: &Meta) { fn set_cache(meta: &Meta) {
let _ = CACHE.lock().map(|mut cache| *cache = Some(meta.clone())); let _ = CACHE.lock().map(|mut cache| *cache = Some(meta.clone()));
} }
#[crate::export] #[crate::export]
pub async fn fetch_meta(use_cache: bool) -> Result<Meta, DbErr> { pub async fn fetch_meta() -> Result<Meta, DbErr> {
fetch_meta_impl(true).await
}
#[crate::export]
pub async fn update_meta_cache() -> Result<(), DbErr> {
fetch_meta_impl(false).await?;
Ok(())
}
async fn fetch_meta_impl(use_cache: bool) -> Result<Meta, DbErr> {
// try using cache // try using cache
if use_cache { if use_cache {
if let Some(cache) = CACHE.lock().ok().and_then(|cache| cache.clone()) { if let Some(cache) = CACHE.lock().ok().and_then(|cache| cache.clone()) {
@ -24,7 +34,7 @@ pub async fn fetch_meta(use_cache: bool) -> Result<Meta, DbErr> {
let db = db_conn().await?; let db = db_conn().await?;
let meta = meta::Entity::find().one(db).await?; let meta = meta::Entity::find().one(db).await?;
if let Some(meta) = meta { if let Some(meta) = meta {
update_cache(&meta); set_cache(&meta);
return Ok(meta); return Ok(meta);
} }
@ -35,7 +45,7 @@ pub async fn fetch_meta(use_cache: bool) -> Result<Meta, DbErr> {
}) })
.exec_with_returning(db) .exec_with_returning(db)
.await?; .await?;
update_cache(&meta); set_cache(&meta);
Ok(meta) Ok(meta)
} }

View file

@ -118,7 +118,7 @@ pub async fn to_db_reaction(reaction: Option<&str>, host: Option<&str>) -> Resul
}; };
}; };
Ok(fetch_meta(true).await?.default_reaction) Ok(fetch_meta().await?.default_reaction)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -197,7 +197,7 @@ pub async fn send_push_notification(
kind: PushNotificationKind, kind: PushNotificationKind,
content: &serde_json::Value, content: &serde_json::Value,
) -> Result<(), Error> { ) -> Result<(), Error> {
let meta = fetch_meta(true).await?; let meta = fetch_meta().await?;
if !meta.enable_service_worker || meta.sw_public_key.is_none() || meta.sw_private_key.is_none() if !meta.enable_service_worker || meta.sw_public_key.is_none() || meta.sw_private_key.is_none()
{ {

View file

@ -1,23 +1,19 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Firefish API</title> <title>Firefish API</title>
<!-- needed for adaptive design --> <!-- Embed elements Elements via Web Component -->
<meta charset="utf-8"/> <script src="https://unpkg.com/@stoplight/elements/web-components.min.js" crossorigin="anonymous"></script>
<meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css">
<!--
ReDoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head> </head>
<body> <body>
<redoc spec-url="/api.json" expand-responses="200" expand-single-schema-field="true"></redoc> <elements-api
<script src="https://cdn.jsdelivr.net/npm/redoc@2.0.0-rc.50/bundles/redoc.standalone.js" integrity="sha256-WJbngBWN9vp6vkEuzeoSj5tE5saW9Hfj6/SinkzhL2s=" crossorigin="anonymous"></script> id="element-main"
apiDescriptionUrl='/api.json'
router="hash"
layout="responsive"
/>
</body> </body>
</html> </html>

View file

@ -4,10 +4,10 @@ import semver from "semver";
import Logger from "@/services/logger.js"; import Logger from "@/services/logger.js";
import { import {
fetchMeta,
greet, greet,
removeOldAttestationChallenges, removeOldAttestationChallenges,
showServerInfo, showServerInfo,
updateMetaCache,
type Config, type Config,
} from "backend-rs"; } from "backend-rs";
import { config, envOption } from "@/config.js"; import { config, envOption } from "@/config.js";
@ -53,7 +53,7 @@ export async function masterMain() {
import("../daemons/server-stats.js").then((x) => x.default()); import("../daemons/server-stats.js").then((x) => x.default());
import("../daemons/queue-stats.js").then((x) => x.default()); import("../daemons/queue-stats.js").then((x) => x.default());
// Update meta cache every 5 minitues // Update meta cache every 5 minitues
setInterval(() => fetchMeta(false), 1000 * 60 * 5); setInterval(() => updateMetaCache(), 1000 * 60 * 5);
// Remove old attestation challenges // Remove old attestation challenges
setInterval(() => removeOldAttestationChallenges(), 1000 * 60 * 30); setInterval(() => removeOldAttestationChallenges(), 1000 * 60 * 30);
} }

View file

@ -13,7 +13,7 @@ export default async function () {
ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50)); ev.emit(`serverStatsLog:${x.id}`, log.slice(0, x.length || 50));
}); });
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (!meta.enableServerMachineStats) return; if (!meta.enableServerMachineStats) return;
async function tick() { async function tick() {

View file

@ -3,7 +3,7 @@ import type { ILocalUser } from "@/models/entities/user.js";
import { Users } from "@/models/index.js"; import { Users } from "@/models/index.js";
export async function fetchProxyAccount(): Promise<ILocalUser | null> { export async function fetchProxyAccount(): Promise<ILocalUser | null> {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.proxyAccountId == null) return null; if (meta.proxyAccountId == null) return null;
return (await Users.findOneByOrFail({ return (await Users.findOneByOrFail({
id: meta.proxyAccountId, id: meta.proxyAccountId,

View file

@ -26,7 +26,7 @@ export async function translate(
from: PostLanguage | null, from: PostLanguage | null,
to: PostLanguage, to: PostLanguage,
) { ) {
const instance = await fetchMeta(true); const instance = await fetchMeta();
if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) { if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) {
throw Error("No translator is set up on this server."); throw Error("No translator is set up on this server.");

View file

@ -15,7 +15,7 @@ import type { UserPublickey } from "@/models/entities/user-publickey.js";
import { verify } from "node:crypto"; import { verify } from "node:crypto";
export async function hasSignature(req: IncomingMessage): Promise<string> { export async function hasSignature(req: IncomingMessage): Promise<string> {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const required = meta.secureMode || meta.privateMode; const required = meta.secureMode || meta.privateMode;
try { try {
@ -30,7 +30,7 @@ export async function hasSignature(req: IncomingMessage): Promise<string> {
} }
export async function checkFetch(req: IncomingMessage): Promise<number> { export async function checkFetch(req: IncomingMessage): Promise<number> {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
if (req.headers.host !== config.host) return 400; if (req.headers.host !== config.host) return 400;

View file

@ -36,7 +36,7 @@ export async function createImage(
apLogger.info(`Creating an image: ${image.url}`); apLogger.info(`Creating an image: ${image.url}`);
const instance = await fetchMeta(true); const instance = await fetchMeta();
let file = await uploadFromUrl({ let file = await uploadFromUrl({
url: image.url, url: image.url,

View file

@ -243,7 +243,7 @@ router.get("/notes/:note", async (ctx, next) => {
ctx.body = renderActivity(await renderNote(note, false)); ctx.body = renderActivity(await renderNote(note, false));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -273,7 +273,7 @@ router.get("/notes/:note/activity", async (ctx) => {
} }
ctx.body = renderActivity(await packActivity(note)); ctx.body = renderActivity(await packActivity(note));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -328,7 +328,7 @@ router.get("/users/:user/publickey", async (ctx) => {
if (Users.isLocalUser(user)) { if (Users.isLocalUser(user)) {
ctx.body = renderActivity(renderKey(user, keypair)); ctx.body = renderActivity(renderKey(user, keypair));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -348,7 +348,7 @@ async function userInfo(ctx: Router.RouterContext, user: User | null) {
} }
ctx.body = renderActivity(await renderPerson(user as ILocalUser)); ctx.body = renderActivity(await renderPerson(user as ILocalUser));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -432,7 +432,7 @@ router.get("/emojis/:emoji", async (ctx) => {
} }
ctx.body = renderActivity(renderEmoji(emoji)); ctx.body = renderActivity(renderEmoji(emoji));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -464,7 +464,7 @@ router.get("/likes/:like", async (ctx) => {
} }
ctx.body = renderActivity(await renderLike(reaction, note)); ctx.body = renderActivity(await renderLike(reaction, note));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -502,7 +502,7 @@ router.get(
} }
ctx.body = renderActivity(renderFollow(follower, followee)); ctx.body = renderActivity(renderFollow(follower, followee));
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {
@ -545,7 +545,7 @@ router.get("/follows/:followRequestId", async (ctx: Router.RouterContext) => {
return; return;
} }
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {

View file

@ -57,7 +57,7 @@ export default async (ctx: Router.RouterContext) => {
ctx.body = renderActivity(rendered); ctx.body = renderActivity(rendered);
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {

View file

@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => {
ctx.body = renderActivity(rendered); ctx.body = renderActivity(rendered);
setResponseType(ctx); setResponseType(ctx);
} }
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {

View file

@ -110,7 +110,7 @@ export default async (ctx: Router.RouterContext) => {
ctx.body = renderActivity(rendered); ctx.body = renderActivity(rendered);
setResponseType(ctx); setResponseType(ctx);
} }
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {

View file

@ -117,7 +117,7 @@ export default async (ctx: Router.RouterContext) => {
setResponseType(ctx); setResponseType(ctx);
} }
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.secureMode || meta.privateMode) { if (meta.secureMode || meta.privateMode) {
ctx.set("Cache-Control", "private, max-age=0, must-revalidate"); ctx.set("Cache-Control", "private, max-age=0, must-revalidate");
} else { } else {

View file

@ -84,7 +84,7 @@ export default (endpoint: IEndpoint, ctx: Koa.Context) =>
// Log IP // Log IP
if (user) { if (user) {
fetchMeta(true).then((meta) => { fetchMeta().then((meta) => {
if (!meta.enableIpLogging) return; if (!meta.enableIpLogging) return;
const ip = ctx.ip; const ip = ctx.ip;
const ips = userIpHistories.get(user.id); const ips = userIpHistories.get(user.id);

View file

@ -117,7 +117,7 @@ export default async (
} }
// private mode // private mode
const meta = await fetchMeta(true); const meta = await fetchMeta();
if ( if (
meta.privateMode && meta.privateMode &&
ep.meta.requireCredentialPrivateMode && ep.meta.requireCredentialPrivateMode &&

View file

@ -470,7 +470,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async () => { export default define(meta, paramDef, async () => {
const instance = await fetchMeta(false); const instance = await fetchMeta();
return { return {
maintainerName: instance.maintainerName, maintainerName: instance.maintainerName,

View file

@ -123,7 +123,7 @@ export default define(meta, paramDef, async (ps, user) => {
let userList; let userList;
let userGroupJoining; let userGroupJoining;
const instance = await fetchMeta(true); const instance = await fetchMeta();
const antennas = await Antennas.findBy({ const antennas = await Antennas.findBy({
userId: user.id, userId: user.id,

View file

@ -27,7 +27,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async () => { export default define(meta, paramDef, async () => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const motd = await Promise.all(meta.customMotd.map((x) => x)); const motd = await Promise.all(meta.customMotd.map((x) => x));
return motd; return motd;
}); });

View file

@ -27,7 +27,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async () => { export default define(meta, paramDef, async () => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const icons = await Promise.all(meta.customSplashIcons.map((x) => x)); const icons = await Promise.all(meta.customSplashIcons.map((x) => x));
return icons; return icons;
}); });

View file

@ -35,7 +35,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const instance = await fetchMeta(false); const instance = await fetchMeta();
// Calculate drive usage // Calculate drive usage
const usage = await DriveFiles.calcDriveUsageOf(user.id); const usage = await DriveFiles.calcDriveUsageOf(user.id);

View file

@ -95,7 +95,7 @@ export default define(
name = null; name = null;
} }
const instanceMeta = await fetchMeta(true); const instanceMeta = await fetchMeta();
try { try {
// Create file // Create file

View file

@ -100,7 +100,7 @@ export default define(meta, paramDef, async (ps, me) => {
} }
if (typeof ps.blocked === "boolean") { if (typeof ps.blocked === "boolean") {
const meta = await fetchMeta(false); const meta = await fetchMeta();
if (ps.blocked) { if (ps.blocked) {
if (meta.blockedHosts.length === 0) { if (meta.blockedHosts.length === 0) {
return []; return [];
@ -116,7 +116,7 @@ export default define(meta, paramDef, async (ps, me) => {
} }
if (typeof ps.silenced === "boolean") { if (typeof ps.silenced === "boolean") {
const meta = await fetchMeta(false); const meta = await fetchMeta();
if (ps.silenced) { if (ps.silenced) {
if (meta.silencedHosts.length === 0) { if (meta.silencedHosts.length === 0) {
return []; return [];

View file

@ -66,7 +66,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async () => { export default define(meta, paramDef, async () => {
const instance = await fetchMeta(false); const instance = await fetchMeta();
const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t)); const hiddenTags = instance.hiddenTags.map((t) => normalizeForSearch(t));
const now = new Date(); // 5分単位で丸めた現在日時 const now = new Date(); // 5分単位で丸めた現在日時

View file

@ -44,7 +44,7 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const file = await DriveFiles.findOneBy({ id: ps.fileId }); const file = await DriveFiles.findOneBy({ id: ps.fileId });
const instanceMeta = await fetchMeta(true); const instanceMeta = await fetchMeta();
if (instanceMeta.experimentalFeatures?.postImports === false) if (instanceMeta.experimentalFeatures?.postImports === false)
throw new ApiError(meta.errors.importsDisabled); throw new ApiError(meta.errors.importsDisabled);

View file

@ -402,7 +402,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const instance = await fetchMeta(false); const instance = await fetchMeta();
const emojis = await Emojis.find({ const emojis = await Emojis.find({
where: { where: {

View file

@ -64,7 +64,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const m = await fetchMeta(true); const m = await fetchMeta();
if (m.disableGlobalTimeline) { if (m.disableGlobalTimeline) {
if (user == null || !(user.isAdmin || user.isModerator)) { if (user == null || !(user.isAdmin || user.isModerator)) {
throw new ApiError(meta.errors.gtlDisabled); throw new ApiError(meta.errors.gtlDisabled);

View file

@ -71,7 +71,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const m = await fetchMeta(true); const m = await fetchMeta();
if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) {
throw new ApiError(meta.errors.stlDisabled); throw new ApiError(meta.errors.stlDisabled);
} }

View file

@ -74,7 +74,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const m = await fetchMeta(true); const m = await fetchMeta();
if (m.disableLocalTimeline) { if (m.disableLocalTimeline) {
if (user == null || !(user.isAdmin || user.isModerator)) { if (user == null || !(user.isAdmin || user.isModerator)) {
throw new ApiError(meta.errors.ltlDisabled); throw new ApiError(meta.errors.ltlDisabled);

View file

@ -74,7 +74,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
const m = await fetchMeta(true); const m = await fetchMeta();
if (m.disableRecommendedTimeline) { if (m.disableRecommendedTimeline) {
if (user == null || !(user.isAdmin || user.isModerator)) { if (user == null || !(user.isAdmin || user.isModerator)) {
throw new ApiError(meta.errors.rtlDisabled); throw new ApiError(meta.errors.rtlDisabled);

View file

@ -30,7 +30,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async (ps, me) => { export default define(meta, paramDef, async (ps, me) => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const users = await Promise.all( const users = await Promise.all(
meta.pinnedUsers meta.pinnedUsers

View file

@ -27,7 +27,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async () => { export default define(meta, paramDef, async () => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const instances = await Promise.all(meta.recommendedInstances.map((x) => x)); const instances = await Promise.all(meta.recommendedInstances.map((x) => x));
return instances; return instances;
}); });

View file

@ -17,7 +17,7 @@ export const paramDef = {
} as const; } as const;
export default define(meta, paramDef, async () => { export default define(meta, paramDef, async () => {
const instanceMeta = await fetchMeta(true); const instanceMeta = await fetchMeta();
if (!instanceMeta.enableServerMachineStats) { if (!instanceMeta.enableServerMachineStats) {
return { return {

View file

@ -63,7 +63,7 @@ export default define(meta, paramDef, async (ps, me) => {
publickey: ps.publickey, publickey: ps.publickey,
}); });
const instance = await fetchMeta(false); const instance = await fetchMeta();
// if already subscribed // if already subscribed
if (subscription != null) { if (subscription != null) {

View file

@ -101,7 +101,7 @@ export function genOpenapiSpec() {
} }
const info = { const info = {
operationId: endpoint.name, operationId: `POST-${endpoint.name}`,
summary: endpoint.name, summary: endpoint.name,
description: desc, description: desc,
externalDocs: { externalDocs: {
@ -208,11 +208,11 @@ export function genOpenapiSpec() {
}, },
}; };
const path = { const path: Record<string, typeof info> = {
post: info, post: info,
}; };
if (endpoint.meta.allowGet) { if (endpoint.meta.allowGet) {
path.get = { ...info }; path.get = { ...info, operationId: `GET-${endpoint.name}` };
// API Key authentication is not permitted for GET requests // API Key authentication is not permitted for GET requests
path.get.security = path.get.security.filter( path.get.security = path.get.security.filter(
(elem) => !Object.prototype.hasOwnProperty.call(elem, "ApiKeyAuth"), (elem) => !Object.prototype.hasOwnProperty.call(elem, "ApiKeyAuth"),

View file

@ -11,7 +11,7 @@ import { validateEmailForAccount } from "@/services/validate-email-for-account.j
export default async (ctx: Koa.Context) => { export default async (ctx: Koa.Context) => {
const body = ctx.request.body; const body = ctx.request.body;
const instance = await fetchMeta(false); const instance = await fetchMeta();
// Verify *Captcha // Verify *Captcha
// ただしテスト時はこの機構は障害となるため無効にする // ただしテスト時はこの機構は障害となるため無効にする

View file

@ -16,7 +16,7 @@ export default class extends Channel {
} }
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.disableGlobalTimeline) { if (meta.disableGlobalTimeline) {
if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) if (this.user == null || !(this.user.isAdmin || this.user.isModerator))
return; return;

View file

@ -16,7 +16,7 @@ export default class extends Channel {
} }
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if ( if (
meta.disableLocalTimeline && meta.disableLocalTimeline &&
!this.user!.isAdmin && !this.user!.isAdmin &&

View file

@ -15,7 +15,7 @@ export default class extends Channel {
} }
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.disableLocalTimeline) { if (meta.disableLocalTimeline) {
if (this.user == null || !(this.user.isAdmin || this.user.isModerator)) if (this.user == null || !(this.user.isAdmin || this.user.isModerator))
return; return;

View file

@ -16,7 +16,7 @@ export default class extends Channel {
} }
public async init(params: any) { public async init(params: any) {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if ( if (
meta.disableRecommendedTimeline && meta.disableRecommendedTimeline &&
!this.user!.isAdmin && !this.user!.isAdmin &&
@ -36,7 +36,7 @@ export default class extends Channel {
// チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または // チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または
// チャンネルの投稿ではなく、全体公開のローカルの投稿 または // チャンネルの投稿ではなく、全体公開のローカルの投稿 または
// フォローしているチャンネルの投稿 の場合だけ // フォローしているチャンネルの投稿 の場合だけ
const meta = await fetchMeta(true); const meta = await fetchMeta();
if ( if (
!( !(
note.user.host != null && note.user.host != null &&

View file

@ -126,7 +126,7 @@ router.get("/avatar/@:acct", async (ctx) => {
}); });
router.get("/identicon/:x", async (ctx) => { router.get("/identicon/:x", async (ctx) => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.enableIdenticonGeneration) { if (meta.enableIdenticonGeneration) {
const [temp, cleanup] = await createTemp(); const [temp, cleanup] = await createTemp();
await genIdenticon(ctx.params.x, fs.createWriteStream(temp)); await genIdenticon(ctx.params.x, fs.createWriteStream(temp));

View file

@ -334,7 +334,7 @@ const getFeed = async (
noRenotes: string, noRenotes: string,
noReplies: string, noReplies: string,
) => { ) => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.privateMode) { if (meta.privateMode) {
return; return;
} }
@ -482,7 +482,7 @@ const userPage: Router.Middleware = async (ctx, next) => {
} }
const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
const meta = await fetchMeta(true); const meta = await fetchMeta();
const me = profile.fields const me = profile.fields
? profile.fields ? profile.fields
.filter((filed) => filed.value?.match(/^https?:/)) .filter((filed) => filed.value?.match(/^https?:/))
@ -531,7 +531,7 @@ router.get("/notes/:note", async (ctx, next) => {
const profile = await UserProfiles.findOneByOrFail({ const profile = await UserProfiles.findOneByOrFail({
userId: note.userId, userId: note.userId,
}); });
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("note", { await ctx.render("note", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),
note: packedNote, note: packedNote,
@ -565,7 +565,7 @@ router.get("/posts/:note", async (ctx, next) => {
if (note) { if (note) {
const _note = await Notes.pack(note); const _note = await Notes.pack(note);
const profile = await UserProfiles.findOneByOrFail({ userId: note.userId }); const profile = await UserProfiles.findOneByOrFail({ userId: note.userId });
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("note", { await ctx.render("note", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),
note: _note, note: _note,
@ -603,7 +603,7 @@ router.get("/@:user/pages/:page", async (ctx, next) => {
if (page) { if (page) {
const _page = await Pages.pack(page); const _page = await Pages.pack(page);
const profile = await UserProfiles.findOneByOrFail({ userId: page.userId }); const profile = await UserProfiles.findOneByOrFail({ userId: page.userId });
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("page", { await ctx.render("page", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),
page: _page, page: _page,
@ -635,7 +635,7 @@ router.get("/clips/:clip", async (ctx, next) => {
if (clip) { if (clip) {
const _clip = await Clips.pack(clip); const _clip = await Clips.pack(clip);
const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId }); const profile = await UserProfiles.findOneByOrFail({ userId: clip.userId });
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("clip", { await ctx.render("clip", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),
clip: _clip, clip: _clip,
@ -660,7 +660,7 @@ router.get("/gallery/:post", async (ctx, next) => {
if (post) { if (post) {
const _post = await GalleryPosts.pack(post); const _post = await GalleryPosts.pack(post);
const profile = await UserProfiles.findOneByOrFail({ userId: post.userId }); const profile = await UserProfiles.findOneByOrFail({ userId: post.userId });
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("gallery-post", { await ctx.render("gallery-post", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),
post: _post, post: _post,
@ -686,7 +686,7 @@ router.get("/channels/:channel", async (ctx, next) => {
if (channel) { if (channel) {
const _channel = await Channels.pack(channel); const _channel = await Channels.pack(channel);
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("channel", { await ctx.render("channel", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),
channel: _channel, channel: _channel,
@ -739,7 +739,7 @@ router.get("/api/v1/streaming", async (ctx) => {
// Render base html for all requests // Render base html for all requests
router.get("(.*)", async (ctx) => { router.get("(.*)", async (ctx) => {
const meta = await fetchMeta(true); const meta = await fetchMeta();
await ctx.render("base", { await ctx.render("base", {
...metaToPugArgs(meta), ...metaToPugArgs(meta),

View file

@ -77,7 +77,7 @@ const manifest = {
}; };
export const manifestHandler = async (ctx: Koa.Context) => { export const manifestHandler = async (ctx: Koa.Context) => {
const instance = await fetchMeta(true); const instance = await fetchMeta();
manifest.short_name = instance.name || "Firefish"; manifest.short_name = instance.name || "Firefish";
manifest.name = instance.name || "Firefish"; manifest.name = instance.name || "Firefish";

View file

@ -22,7 +22,7 @@ export const urlPreviewHandler = async (ctx: Koa.Context) => {
return; return;
} }
const meta = await fetchMeta(true); const meta = await fetchMeta();
logger.info( logger.info(
meta.summalyProxy meta.summalyProxy

View file

@ -78,7 +78,7 @@ async function save(
// thunbnail, webpublic を必要なら生成 // thunbnail, webpublic を必要なら生成
const alts = await generateAlts(path, type, !file.uri); const alts = await generateAlts(path, type, !file.uri);
const meta = await fetchMeta(true); const meta = await fetchMeta();
if (meta.useObjectStorage) { if (meta.useObjectStorage) {
//#region ObjectStorage params //#region ObjectStorage params
@ -363,7 +363,7 @@ async function upload(
if (type === "image/apng") type = "image/png"; if (type === "image/apng") type = "image/png";
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = "application/octet-stream"; if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = "application/octet-stream";
const meta = await fetchMeta(true); const meta = await fetchMeta();
const params = { const params = {
Bucket: meta.objectStorageBucket, Bucket: meta.objectStorageBucket,
@ -507,7 +507,7 @@ export async function addFile({
const usage = await DriveFiles.calcDriveUsageOf(user); const usage = await DriveFiles.calcDriveUsageOf(user);
const u = await Users.findOneBy({ id: user.id }); const u = await Users.findOneBy({ id: user.id });
const instance = await fetchMeta(true); const instance = await fetchMeta();
let driveCapacity = let driveCapacity =
1024 * 1024 *
1024 * 1024 *
@ -579,7 +579,7 @@ export async function addFile({
: null; : null;
const folder = await fetchFolder(); const folder = await fetchFolder();
const instance = await fetchMeta(true); const instance = await fetchMeta();
let file = new DriveFile(); let file = new DriveFile();
file.id = genId(); file.id = genId();

View file

@ -82,7 +82,7 @@ async function postProcess(file: DriveFile, isExpired = false) {
} }
export async function deleteObjectStorageFile(key: string) { export async function deleteObjectStorageFile(key: string) {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const s3 = getS3(meta); const s3 = getS3(meta);

View file

@ -12,7 +12,7 @@ export async function sendEmail(
html: string, html: string,
text: string, text: string,
) { ) {
const meta = await fetchMeta(false); const meta = await fetchMeta();
const iconUrl = `${config.url}/static-assets/mi-white.png`; const iconUrl = `${config.url}/static-assets/mi-white.png`;
const emailSettingUrl = `${config.url}/settings/email`; const emailSettingUrl = `${config.url}/settings/email`;

View file

@ -6,7 +6,7 @@ export async function validateEmailForAccount(emailAddress: string): Promise<{
available: boolean; available: boolean;
reason: null | "used" | "format" | "disposable" | "mx" | "smtp"; reason: null | "used" | "format" | "disposable" | "mx" | "smtp";
}> { }> {
const meta = await fetchMeta(true); const meta = await fetchMeta();
const exist = await UserProfiles.countBy({ const exist = await UserProfiles.countBy({
emailVerified: true, emailVerified: true,