diff --git a/packages/pl-api/lib/entities/instance.ts b/packages/pl-api/lib/entities/instance.ts index f5e018ffd..9d1f7a232 100644 --- a/packages/pl-api/lib/entities/instance.ts +++ b/packages/pl-api/lib/entities/instance.ts @@ -188,18 +188,36 @@ const pleromaSchema = coerceObject({ federation: coerceObject({ enabled: v.fallback(v.boolean(), true), // Assume true unless explicitly false mrf_policies: v.fallback(v.optional(v.array(v.string())), undefined), - mrf_simple: coerceObject({ - accept: v.fallback(v.array(v.string()), []), - avatar_removal: v.fallback(v.array(v.string()), []), - banner_removal: v.fallback(v.array(v.string()), []), - federated_timeline_removal: v.fallback(v.array(v.string()), []), - followers_only: v.fallback(v.array(v.string()), []), - media_nsfw: v.fallback(v.array(v.string()), []), - media_removal: v.fallback(v.array(v.string()), []), - reject: v.fallback(v.array(v.string()), []), - reject_deletes: v.fallback(v.array(v.string()), []), - report_removal: v.fallback(v.array(v.string()), []), - }), + mrf_simple: coerceObject(v.entriesFromList( + [ + 'accept', + 'avatar_removal', + 'banner_removal', + 'federated_timeline_removal', + 'followers_only', + 'media_nsfw', + 'media_removal', + 'reject', + 'reject_deletes', + 'report_removal', + ], + v.fallback(v.array(v.string()), []), + )), + mrf_simple_info: coerceObject(v.entriesFromList( + [ + 'accept', + 'avatar_removal', + 'banner_removal', + 'federated_timeline_removal', + 'followers_only', + 'media_nsfw', + 'media_removal', + 'reject', + 'reject_deletes', + 'report_removal', + ], + v.fallback(v.array(v.tuple([v.string(), v.string()])), []), + )), }), fields_limits: coerceObject({ max_fields: v.fallback(v.pipe(v.number(), v.integer(), v.minValue(0)), 4), diff --git a/packages/pl-fe/src/actions/mrf.ts b/packages/pl-fe/src/actions/mrf.ts index 6b16312d6..3a5fecb32 100644 --- a/packages/pl-fe/src/actions/mrf.ts +++ b/packages/pl-fe/src/actions/mrf.ts @@ -1,26 +1,33 @@ +import { mrfSimpleSchema, type MRFSimple } from 'pl-fe/schemas/pleroma'; import ConfigDB from 'pl-fe/utils/config-db'; import { fetchConfig, updateConfig } from './admin'; -import type { MRFSimple } from 'pl-fe/schemas/pleroma'; import type { AppDispatch, RootState } from 'pl-fe/store'; -const simplePolicyMerge = (simplePolicy: MRFSimple, host: string, restrictions: Record) => { +const simplePolicyMerge = (simplePolicy: Partial, host: string, restrictions: Record): MRFSimple => { const entries = Object.entries(simplePolicy).map(([key, hosts]) => { const isRestricted = restrictions[key]; - const set = new Set(hosts); + hosts = [...hosts]; if (isRestricted) { - set.add(host); + if (!hosts.some((tuple) => tuple[0] === host)) { + hosts.push([host, '']); + } } else { - set.delete(host); + hosts = hosts.filter((tuple) => tuple[0] !== host); } - return [key, [...set]]; + return [key, hosts]; }); - return Object.fromEntries(entries); + return Object.fromEntries([ + ...Object.keys( + (mrfSimpleSchema as any).wrapped.pipe[2].entries as typeof mrfSimpleSchema.entries, + ).map((key) => [key, []]), + ...entries, + ]); }; const updateMrf = (host: string, restrictions: Record) => diff --git a/packages/pl-fe/src/pages/utils/federation-restrictions.tsx b/packages/pl-fe/src/pages/utils/federation-restrictions.tsx index 943d4d46b..5e9d3ccd5 100644 --- a/packages/pl-fe/src/pages/utils/federation-restrictions.tsx +++ b/packages/pl-fe/src/pages/utils/federation-restrictions.tsx @@ -47,7 +47,7 @@ const FederationRestrictionsPage = () => {
- {hosts.map((host) => )} + {hosts.map(([host]) => )}
diff --git a/packages/pl-fe/src/reducers/instance.ts b/packages/pl-fe/src/reducers/instance.ts index d0261a228..938155011 100644 --- a/packages/pl-fe/src/reducers/instance.ts +++ b/packages/pl-fe/src/reducers/instance.ts @@ -32,9 +32,8 @@ const getConfigValue = (instanceConfig: Array, key: string) => { const importConfigs = (state: State, configs: PleromaConfig['configs']) => { // FIXME: This is pretty hacked together. Need to make a cleaner map. const config = ConfigDB.find(configs, ':pleroma', ':instance'); - const simplePolicy = ConfigDB.toSimplePolicy(configs); - if (!config && !simplePolicy) return state; + if (!config) return state; if (config) { const value = config.value || []; @@ -47,10 +46,6 @@ const importConfigs = (state: State, configs: PleromaConfig['configs']) => { approval_required: approvalRequired ?? state.registrations.approval_required, }; } - - if (simplePolicy) { - state.pleroma.metadata.federation.mrf_simple = simplePolicy; - } }; const handleAuthFetch = (state: State) => { diff --git a/packages/pl-fe/src/schemas/pleroma.ts b/packages/pl-fe/src/schemas/pleroma.ts index 20f7a2a05..869d6ff9a 100644 --- a/packages/pl-fe/src/schemas/pleroma.ts +++ b/packages/pl-fe/src/schemas/pleroma.ts @@ -2,6 +2,11 @@ import * as v from 'valibot'; import { coerceObject } from './utils'; +const mrfSimpleInstanceSchema = v.pipe(v.any(), v.transform((value) => { + if (typeof value === 'string') return [value, '']; + return value.tuple; +}), v.tuple([v.string(), v.string()])); + const mrfSimpleSchema = coerceObject(v.entriesFromList( [ 'accept', @@ -15,7 +20,7 @@ const mrfSimpleSchema = coerceObject(v.entriesFromList( 'reject_deletes', 'report_removal', ], - v.fallback(v.array(v.string()), []), + v.fallback(v.array(mrfSimpleInstanceSchema), []), )); type MRFSimple = v.InferOutput; diff --git a/packages/pl-fe/src/selectors/index.ts b/packages/pl-fe/src/selectors/index.ts index 090dbc01a..c98a05c81 100644 --- a/packages/pl-fe/src/selectors/index.ts +++ b/packages/pl-fe/src/selectors/index.ts @@ -1,6 +1,5 @@ import { createSelector } from 'reselect'; -// import { getLocale } from 'pl-fe/actions/settings'; import { Entities } from 'pl-fe/entity-store/entities'; import { useSettingsStore } from 'pl-fe/stores/settings'; import { getDomain } from 'pl-fe/utils/accounts'; @@ -245,8 +244,8 @@ const makeGetOtherAccounts = () => createSelector([ const getSimplePolicy = createSelector([ (state: RootState) => state.admin.configs, - (state: RootState) => state.instance.pleroma.metadata.federation.mrf_simple, -], (configs, instancePolicy) => ({ + (state: RootState) => state.instance.pleroma.metadata.federation.mrf_simple_info, +], (configs, instancePolicy): MRFSimple => ({ ...instancePolicy, ...ConfigDB.toSimplePolicy(configs), })); @@ -265,7 +264,7 @@ const getRemoteInstanceFederation = (state: RootState, host: string): HostFedera const simplePolicy = getSimplePolicy(state); return Object.fromEntries( - Object.entries(simplePolicy).map(([key, hosts]) => [key, hosts.includes(host)]), + Object.entries(simplePolicy).map(([key, hosts]) => [key, hosts.some(entry => entry[0] === host)]), ) as HostFederation; }; diff --git a/packages/pl-fe/src/utils/config-db.ts b/packages/pl-fe/src/utils/config-db.ts index 0b01a015d..8f7e0e122 100644 --- a/packages/pl-fe/src/utils/config-db.ts +++ b/packages/pl-fe/src/utils/config-db.ts @@ -1,7 +1,7 @@ import trimStart from 'lodash/trimStart'; import * as v from 'valibot'; -import { mrfSimpleSchema } from 'pl-fe/schemas/pleroma'; +import { mrfSimpleSchema, type MRFSimple } from 'pl-fe/schemas/pleroma'; import type { PleromaConfig } from 'pl-api'; @@ -16,13 +16,14 @@ const find = ( config.group === group && config.key === key, ); -const toSimplePolicy = (configs: PleromaConfig['configs']) => { +const toSimplePolicy = (configs: PleromaConfig['configs']): Partial => { const config = find(configs, ':pleroma', ':mrf_simple'); const reducer = (acc: Record, curr: Record) => { const key = curr.tuple?.[0] as string; const hosts = curr.tuple?.[1] as Array; - return acc[trimStart(key, ':')] = hosts; + acc[trimStart(key, ':')] = hosts; + return acc; }; if (config) { @@ -30,12 +31,12 @@ const toSimplePolicy = (configs: PleromaConfig['configs']) => { const result = value.reduce(reducer, {}); return v.parse(mrfSimpleSchema, result); } else { - return v.parse(mrfSimpleSchema, {}); + return {}; } }; const fromSimplePolicy = (simplePolicy: Policy) => { - const mapper = ([key, hosts]: [key: string, hosts: Array]) => ({ tuple: [`:${key}`, hosts] }); + const mapper = ([key, hosts]: [key: string, hosts: Array<[string, string]>]) => ({ tuple: [`:${key}`, hosts.map(host => ({ tuple: host }))] }); const value = Object.entries(simplePolicy).map(mapper);