forked from FoundKeyGang/FoundKey
Compare commits
98 commits
Author | SHA1 | Date | |
---|---|---|---|
Jeder | 7c3e9fad6b | ||
Jeder | d282ddc47b | ||
Jeder | 3348a2ad96 | ||
Jeder | 80d36c4ec4 | ||
Jeder | 788b19cd1e | ||
Jeder | 76a9d165cb | ||
Jeder | 6ce3e41eb6 | ||
Jeder | 691379c4f5 | ||
Jeder | 0537312e95 | ||
Jeder | b99d2aea68 | ||
Jeder | f9811eb62a | ||
Jeder | 556f190ccb | ||
Johann150 | 7a82a3d262 | ||
Jeder | 7518ede6e8 | ||
Jeder | 54bfc890e3 | ||
Johann150 | 45ee9951dc | ||
Johann150 | cd87e262fe | ||
Johann150 | 23953b9ad1 | ||
Johann150 | db0e6a241c | ||
Johann150 | 0c3c855d29 | ||
Jeder | 408382cb14 | ||
Jeder | bfdffa6c66 | ||
Jeder | c54a513879 | ||
Jeder | 4c6cf88d38 | ||
Jeder | ba83032bfa | ||
Jeder | 3eeee88973 | ||
Jeder | 6edf5928e9 | ||
Norm | 8aee4bb4d8 | ||
nullobsi | 86355f948c | ||
nullobsi | a0525cb8ec | ||
nullobsi | fdbc72130f | ||
nullobsi | e465ea8103 | ||
nullobsi | 3f438bcdab | ||
Jeder | 43253171f4 | ||
Michcio | 1dcced3668 | ||
Jeder | 62c627a542 | ||
Jeder | 6acc27e2c5 | ||
Chloe Kudryavtsev | 3c1d0cc8dc | ||
Michcio | fd7121f5f0 | ||
Jeder | dd8bcce32f | ||
Jeder | 437c142502 | ||
Jeder | ddde9d5041 | ||
Jeder | 1a386d8bb6 | ||
Jeder | 9ec76d450f | ||
Jeder | 618a0c4ace | ||
Jeder | 78f4b90145 | ||
Puniko | b6f3cbd807 | ||
Jędrzej Tomaszewski | 7dc64edfb0 | ||
Michcio | 4bcf50356d | ||
Michcio | e0b686ece3 | ||
Michcio | 3232a9d0c7 | ||
Jędrzej Tomaszewski | c19532e193 | ||
Jędrzej Tomaszewski | 27c24dfd93 | ||
Jędrzej Tomaszewski | d19b7129e9 | ||
Jędrzej Tomaszewski | 682a338b06 | ||
Jędrzej Tomaszewski | db02477874 | ||
Jędrzej Tomaszewski | 6d42caef44 | ||
Jędrzej Tomaszewski | 320433a579 | ||
Jędrzej Tomaszewski | 3b5a6608e0 | ||
Jędrzej Tomaszewski | 13cc027c95 | ||
Jędrzej Tomaszewski | 0c01443d42 | ||
Michcio | e2a019a197 | ||
Michcio | 97701c9432 | ||
Michał Sidor | f06d351576 | ||
Jędrzej Tomaszewski | 1d8fca7c1d | ||
Jędrzej Tomaszewski | eea3652871 | ||
Jędrzej Tomaszewski | 8b3bfdf927 | ||
Jędrzej Tomaszewski | 768164a753 | ||
Jędrzej Tomaszewski | 89839a989e | ||
nullobsi | 9ed1a09e8c | ||
nullobsi | f6d184ca34 | ||
nullobsi | 6ec798cb80 | ||
nullobsi | 1be82f6992 | ||
nullobsi | 6e45571807 | ||
Jędrzej Tomaszewski | 44292e7a91 | ||
Jędrzej Tomaszewski | 5e0ebd79de | ||
Jędrzej Tomaszewski | cc74dce2d0 | ||
Jędrzej Tomaszewski | bd0325b40d | ||
Jędrzej Tomaszewski | 1e4881d47f | ||
Jędrzej Tomaszewski | 280421c105 | ||
d87207eaa3 | |||
Jędrzej Tomaszewski | f769f58231 | ||
Jędrzej Tomaszewski | 47119c4309 | ||
Jędrzej Tomaszewski | 6abf536801 | ||
Johann150 | b874ca55e3 | ||
Jędrzej Tomaszewski | 58c27a5049 | ||
Jędrzej Tomaszewski | d7fe6b8af2 | ||
Jędrzej Tomaszewski | 311f8af433 | ||
Jędrzej Tomaszewski | 27680ba04c | ||
Jędrzej Tomaszewski | b41315e87f | ||
Jędrzej Tomaszewski | 9bd9f1f2b0 | ||
Jędrzej Tomaszewski | c0563c7931 | ||
Jędrzej Tomaszewski | bdaae6b096 | ||
Jędrzej Tomaszewski | 2a4febaa5f | ||
Jędrzej Tomaszewski | faea9a939a | ||
Jędrzej Tomaszewski | 5de0db8910 | ||
Jędrzej Tomaszewski | a1cb1d27ab | ||
Jędrzej Tomaszewski | 0fdc71f224 |
|
@ -293,9 +293,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "الصفحات"
|
||||
integration: "التكامل"
|
||||
connectService: "اتصل"
|
||||
disconnectService: "اقطع الاتصال"
|
||||
enableLocalTimeline: "تفعيل الخيط المحلي"
|
||||
enableGlobalTimeline: "تفعيل الخيط الزمني الشامل"
|
||||
disablingTimelinesInfo: "سيتمكن المديرون والمشرفون من الوصول إلى كل الخيوط الزمنية\
|
||||
|
|
|
@ -308,9 +308,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "পৃষ্ঠা"
|
||||
integration: "ইন্টিগ্রেশন"
|
||||
connectService: "সংযুক্ত করুন"
|
||||
disconnectService: "সংযোগ বিচ্ছিন্ন করুন"
|
||||
enableLocalTimeline: "স্থানীয় টাইমলাইন চালু করুন"
|
||||
enableGlobalTimeline: "গ্লোবাল টাইমলাইন চালু করুন"
|
||||
disablingTimelinesInfo: "আপনি এই টাইমলাইনগুলি বন্ধ করলেও প্রশাসক এবং মডারেটররা এই\
|
||||
|
|
|
@ -277,9 +277,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Stránky"
|
||||
integration: "Integrace"
|
||||
connectService: "Připojit"
|
||||
disconnectService: "Odpojit"
|
||||
enableLocalTimeline: "Povolit lokální čas"
|
||||
enableGlobalTimeline: "Povolit globální čas"
|
||||
enableRegistration: "Povolit registraci novým uživatelům"
|
||||
|
|
|
@ -319,9 +319,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Seiten"
|
||||
integration: "Integration"
|
||||
connectService: "Verbinden"
|
||||
disconnectService: "Trennen"
|
||||
enableLocalTimeline: "Lokale Chronik aktivieren"
|
||||
enableGlobalTimeline: "Globale Chronik aktivieren"
|
||||
disablingTimelinesInfo: "Administratoren und Moderatoren haben immer Zugriff auf alle\
|
||||
|
|
1353
locales/en-GB.yml
Normal file
1353
locales/en-GB.yml
Normal file
File diff suppressed because it is too large
Load diff
|
@ -311,9 +311,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Pages"
|
||||
integration: "Integration"
|
||||
connectService: "Connect"
|
||||
disconnectService: "Disconnect"
|
||||
enableLocalTimeline: "Enable local timeline"
|
||||
enableGlobalTimeline: "Enable global timeline"
|
||||
disablingTimelinesInfo: "Adminstrators and Moderators will always have access to all\
|
||||
|
@ -729,6 +726,13 @@ popularPosts: "Popular posts"
|
|||
shareWithNote: "Share with note"
|
||||
emailNotConfiguredWarning: "Email address not set."
|
||||
ratio: "Ratio"
|
||||
secureMode: "Secure Mode (Authorized Fetch)"
|
||||
instanceSecurity: "Instance Security"
|
||||
secureModeInfo: "Requests from other instances must be signed, otherwise notes won't be returned. signToActivityPubGet must be set to true in the other instance's configuration file."
|
||||
privateMode: "Private Mode"
|
||||
privateModeInfo: "When enabled, only authorized instances may fetch notes. Hides all notes from public."
|
||||
allowedInstances: "Allowed Instances"
|
||||
allowedInstancesDescription: "Set the hosts of the instances you want to allow, separated by line. Valid in private mode only."
|
||||
previewNoteText: "Show preview"
|
||||
customCss: "Custom CSS"
|
||||
customCssWarn: "This setting should only be used if you know what it does. Entering\
|
||||
|
@ -1341,16 +1345,6 @@ _deck:
|
|||
list: "List"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct notes"
|
||||
_services:
|
||||
_discord:
|
||||
connected: "Discord: @{username}#{discriminator} connected to FoundKey: @{mkUsername}!"
|
||||
disconnected: "Discord linkage has been removed."
|
||||
_twitter:
|
||||
connected: "Twitter: @{twitterUserName} connected to FoundKey: @{userName}!"
|
||||
disconnected: "Twitter linkage has been removed."
|
||||
_github:
|
||||
connected: "GitHub: @{login} connected to FoundKey: @{userName}!"
|
||||
disconnected: "GitHub linkage has been removed."
|
||||
_translationService:
|
||||
_deepl:
|
||||
authKey: "DeepL Auth Key"
|
||||
|
|
|
@ -311,9 +311,6 @@ dayX: "Día {day}"
|
|||
monthX: "Mes {month}"
|
||||
yearX: "Año {year}"
|
||||
pages: "Páginas"
|
||||
integration: "Integración"
|
||||
connectService: "Conectar"
|
||||
disconnectService: "Desconectar"
|
||||
enableLocalTimeline: "Habilitar linea de tiempo local"
|
||||
enableGlobalTimeline: "Habilitar linea de tiempo global"
|
||||
disablingTimelinesInfo: "Aunque se desactiven estas lineas de tiempo, por conveniencia\
|
||||
|
|
|
@ -311,9 +311,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Pages"
|
||||
integration: "Intégrations"
|
||||
connectService: "Connexion"
|
||||
disconnectService: "Déconnexion"
|
||||
enableLocalTimeline: "Activer le fil local"
|
||||
enableGlobalTimeline: "Activer le fil global"
|
||||
disablingTimelinesInfo: "Même si vous désactivez ces fils, les administrateur·rice·s\
|
||||
|
|
|
@ -310,9 +310,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Halaman"
|
||||
integration: "Integrasi"
|
||||
connectService: "Sambungkan"
|
||||
disconnectService: "Putuskan"
|
||||
enableLocalTimeline: "Nyalakan linimasa lokal"
|
||||
enableGlobalTimeline: "Nyalakan linimasa global"
|
||||
disablingTimelinesInfo: "Admin dan Moderator akan selalu memiliki akses ke semua linimasa\
|
||||
|
|
|
@ -22,6 +22,7 @@ const languages = [
|
|||
'cs-CZ',
|
||||
'de-DE',
|
||||
'en-US',
|
||||
'en-GB',
|
||||
'es-ES',
|
||||
'fr-FR',
|
||||
'id-ID',
|
||||
|
|
|
@ -304,9 +304,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Pagine"
|
||||
integration: "App collegate"
|
||||
connectService: "Connessione"
|
||||
disconnectService: "Disconnessione "
|
||||
enableLocalTimeline: "Abilita Timeline locale"
|
||||
enableGlobalTimeline: "Abilita Timeline federata"
|
||||
disablingTimelinesInfo: "Anche se disabiliti queste timeline, gli amministratori e\
|
||||
|
|
|
@ -286,9 +286,6 @@ dayX: "{day}日"
|
|||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "ページ"
|
||||
integration: "連携"
|
||||
connectService: "接続する"
|
||||
disconnectService: "切断する"
|
||||
enableLocalTimeline: "ローカルタイムラインを有効にする"
|
||||
enableGlobalTimeline: "グローバルタイムラインを有効にする"
|
||||
disablingTimelinesInfo: "これらのタイムラインを無効化しても、利便性のため管理者およびモデレーターは引き続き利用することができます。"
|
||||
|
@ -672,6 +669,13 @@ popularPosts: "人気の投稿"
|
|||
shareWithNote: "ノートで共有"
|
||||
emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
|
||||
ratio: "比率"
|
||||
secureMode: "セキュアモード (Authorized Fetch)"
|
||||
instanceSecurity: "インスタンスのセキュリティー"
|
||||
secureModeInfo: "他のインスタンスからリクエストするときに、証明を付けなければ返送しません。他のインスタンスの設定ファイルでsignToActivityPubGetはtrueにしてください。"
|
||||
privateMode: "非公開モード"
|
||||
privateModeInfo: "有効にして、許可されているインスタンスのみがリクエストできます。すべてのノートが公開に非表示にします。"
|
||||
allowedInstances: "許可されたインスタンス"
|
||||
allowedInstancesDescription: "許可したいインスタンスのホストを改行で区切って設定します。非公開モードだけで有効です。"
|
||||
previewNoteText: "本文をプレビュー"
|
||||
customCss: "カスタムCSS"
|
||||
customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。"
|
||||
|
@ -1273,13 +1277,3 @@ _deck:
|
|||
list: "リスト"
|
||||
mentions: "あなた宛て"
|
||||
direct: "ダイレクト"
|
||||
_services:
|
||||
_discord:
|
||||
connected: "Discord: @{username}#{discriminator} を、FoundKey: @{mkUsername} に接続しました!"
|
||||
disconnected: "Discordの連携を解除しました :v:"
|
||||
_twitter:
|
||||
connected: "Twitter: @{twitterUserName} を、FoundKey: @{userName} に接続しました!"
|
||||
disconnected: "Twitterの連携を解除しました :v:"
|
||||
_github:
|
||||
connected: "GitHub: @{login} を、FoundKey: @{userName} に接続しました!"
|
||||
disconnected: "GitHubの連携を解除しました :v:"
|
||||
|
|
|
@ -288,7 +288,6 @@ dayX: "{day}日"
|
|||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "ページ"
|
||||
integration: "連携"
|
||||
enableLocalTimeline: "ローカルタイムラインを使えるようにする"
|
||||
enableGlobalTimeline: "グローバルタイムラインを使えるようにする"
|
||||
disablingTimelinesInfo: "ここらへんのタイムラインを使えんようにしてしもても、管理者とモデレーターは使えるままになってるで、そうやなかったら不便やからな。"
|
||||
|
|
|
@ -315,9 +315,6 @@ dayX: "{day}일"
|
|||
monthX: "{month}월"
|
||||
yearX: "{year}년"
|
||||
pages: "페이지"
|
||||
integration: "연동"
|
||||
connectService: "계정 연동"
|
||||
disconnectService: "계정 연동 해제"
|
||||
enableLocalTimeline: "로컬 타임라인 활성화"
|
||||
enableGlobalTimeline: "글로벌 타임라인 활성화"
|
||||
disablingTimelinesInfo: "특정 타임라인을 비활성화하더라도 관리자 및 모더레이터는 계속 사용할 수 있습니다."
|
||||
|
@ -716,7 +713,6 @@ receiveAnnouncementFromInstance: "이 인스턴스의 알림을 이메일로 수
|
|||
emailNotification: "메일 알림"
|
||||
publish: "게시"
|
||||
inChannelSearch: "채널에서 검색"
|
||||
useReactionPickerForContextMenu: "우클릭하여 리액션 선택기 열기"
|
||||
typingUsers: "{users} 님이 입력하고 있어요.."
|
||||
jumpToSpecifiedDate: "특정 날짜로 이동"
|
||||
showingPastTimeline: "과거의 타임라인을 표시하고 있어요"
|
||||
|
|
|
@ -298,9 +298,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Strony"
|
||||
integration: "Integracja"
|
||||
connectService: "Połącz"
|
||||
disconnectService: "Rozłącz"
|
||||
enableLocalTimeline: "Włącz lokalną oś czasu"
|
||||
enableGlobalTimeline: "Włącz globalną oś czasu"
|
||||
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do\
|
||||
|
|
|
@ -311,9 +311,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Pagini"
|
||||
integration: "Integrare"
|
||||
connectService: "Conectează"
|
||||
disconnectService: "Deconectează"
|
||||
enableLocalTimeline: "Activează cronologia locală"
|
||||
enableGlobalTimeline: "Activeaza cronologia globală"
|
||||
disablingTimelinesInfo: "Administratorii și Moderatorii vor avea mereu access la toate\
|
||||
|
|
|
@ -304,9 +304,6 @@ dayX: "{day} день"
|
|||
monthX: "{month} месяц"
|
||||
yearX: "{year} год"
|
||||
pages: "Страницы"
|
||||
integration: "Интеграция"
|
||||
connectService: "Подключиться"
|
||||
disconnectService: "Отключиться"
|
||||
enableLocalTimeline: "Включить локальную ленту"
|
||||
enableGlobalTimeline: "Включить глобальную ленту"
|
||||
disablingTimelinesInfo: "У администраторов и модераторов есть доступ ко всем лентам,\
|
||||
|
|
|
@ -305,9 +305,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Stránky"
|
||||
integration: "Integrácia"
|
||||
connectService: "Pripojiť"
|
||||
disconnectService: "Odpojiť"
|
||||
enableLocalTimeline: "Povoliť lokálnu časovú os"
|
||||
enableGlobalTimeline: "Povoliť globálnu časovú os"
|
||||
disablingTimelinesInfo: "Administrátori a moderátori majú vždy prístup ku všetkým\
|
||||
|
|
|
@ -305,9 +305,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Сторінки"
|
||||
integration: "Інтеграція"
|
||||
connectService: "Під’єднати"
|
||||
disconnectService: "Відключитися"
|
||||
enableLocalTimeline: "Увімкнути локальну стрічку"
|
||||
enableGlobalTimeline: "Увімкнути глобальну стрічку"
|
||||
disablingTimelinesInfo: "Адміністратори та модератори завжди мають доступ до всіх\
|
||||
|
|
|
@ -305,9 +305,6 @@ dayX: "{day}"
|
|||
monthX: "{month}"
|
||||
yearX: "{year}"
|
||||
pages: "Trang"
|
||||
integration: "Tương tác"
|
||||
connectService: "Kết nối"
|
||||
disconnectService: "Ngắt kết nối"
|
||||
enableLocalTimeline: "Bật bảng tin máy chủ"
|
||||
enableGlobalTimeline: "Bật bảng tin liên hợp"
|
||||
disablingTimelinesInfo: "Quản trị viên và Kiểm duyệt viên luôn có quyền truy cập mọi\
|
||||
|
|
|
@ -284,9 +284,6 @@ dayX: "{day}日"
|
|||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "页面"
|
||||
integration: "关联"
|
||||
connectService: "连接"
|
||||
disconnectService: "断开连接"
|
||||
enableLocalTimeline: "启用本地时间线功能"
|
||||
enableGlobalTimeline: "启用全局时间线"
|
||||
disablingTimelinesInfo: "即使时间线功能被禁用,出于方便,管理员和数据图表也可以继续使用。"
|
||||
|
|
|
@ -284,9 +284,6 @@ dayX: "{day}日"
|
|||
monthX: "{month}月"
|
||||
yearX: "{year}年"
|
||||
pages: "頁面"
|
||||
integration: "整合"
|
||||
connectService: "己連結"
|
||||
disconnectService: "己斷開 "
|
||||
enableLocalTimeline: "開啟本地時間軸"
|
||||
enableGlobalTimeline: "啟用公開時間軸"
|
||||
disablingTimelinesInfo: "即使您關閉了時間線功能,管理員和協調人仍可以繼續使用,以方便您。"
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
|
||||
export class allowlistSecureMode1626733991004 {
|
||||
name = 'allowlistSecureMode1626733991004';
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "allowedHosts" character varying(256) [] default '{}'`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "secureMode" bool default false`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "privateMode" bool default false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "allowedHosts"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "secureMode"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "privateMode"`);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
"ajv": "8.11.0",
|
||||
"archiver": "5.3.1",
|
||||
"autobind-decorator": "2.4.0",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.1165.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "1.1.5",
|
||||
|
@ -146,7 +145,7 @@
|
|||
"@types/node": "18.7.16",
|
||||
"@types/node-fetch": "3.0.3",
|
||||
"@types/nodemailer": "6.4.5",
|
||||
"@types/oauth": "^0.9.1",
|
||||
"@types/opentype.js": "^1.3.4",
|
||||
"@types/pg": "^8.6.5",
|
||||
"@types/pug": "2.0.6",
|
||||
"@types/punycode": "2.1.0",
|
||||
|
|
|
@ -12,3 +12,4 @@ export const DB_MAX_NOTE_TEXT_LENGTH = 8192;
|
|||
* Surrogate pairs count as one
|
||||
*/
|
||||
export const DB_MAX_IMAGE_COMMENT_LENGTH = 2048;
|
||||
|
||||
|
|
|
@ -82,6 +82,21 @@ export class Meta {
|
|||
})
|
||||
public blockedHosts: string[];
|
||||
|
||||
@Column('boolean', {
|
||||
default: false
|
||||
})
|
||||
public secureMode: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false
|
||||
})
|
||||
public privateMode: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 256, array: true, default: '{}'
|
||||
})
|
||||
public allowedHosts: string[];
|
||||
|
||||
@Column('varchar', {
|
||||
length: 512, array: true, default: '{/featured,/channels,/explore,/pages,/about-foundkey}',
|
||||
})
|
||||
|
|
|
@ -38,6 +38,11 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
return `Blocked request: ${host}`;
|
||||
}
|
||||
|
||||
// Only permitted instances if in private mode.
|
||||
if (meta.privateMode && !meta.allowedHosts.includes(host)) {
|
||||
return `Blocked request: ${host}`;
|
||||
}
|
||||
|
||||
const keyIdLower = signature.keyId.toLowerCase();
|
||||
if (keyIdLower.startsWith('acct:')) {
|
||||
return `Old keyId is no longer supported. ${keyIdLower}`;
|
||||
|
|
69
packages/backend/src/remote/activitypub/check-fetch.ts
Normal file
69
packages/backend/src/remote/activitypub/check-fetch.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
import config from '@/config/index.js';
|
||||
import { IncomingMessage } from 'http';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import httpSignature from '@peertube/http-signature';
|
||||
import { URL } from 'url';
|
||||
import { toPuny } from '@/misc/convert-host.js';
|
||||
import DbResolver from '@/remote/activitypub/db-resolver.js';
|
||||
import { getApId } from '@/remote/activitypub/type.js';
|
||||
|
||||
export default async function checkFetch(req: IncomingMessage): Promise<number> {
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
let signature;
|
||||
|
||||
try {
|
||||
signature = httpSignature.parseRequest(req, { 'headers': [] });
|
||||
} catch (e) {
|
||||
return 401;
|
||||
}
|
||||
|
||||
const keyId = new URL(signature.keyId);
|
||||
const host = toPuny(keyId.hostname);
|
||||
|
||||
if (meta.blockedHosts.includes(host)) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
if (meta.privateMode && host !== config.host && !meta.allowedHosts.includes(host)) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
const keyIdLower = signature.keyId.toLowerCase();
|
||||
if (keyIdLower.startsWith('acct:')) {
|
||||
// Old keyId is no longer supported.
|
||||
return 401;
|
||||
}
|
||||
|
||||
const dbResolver = new DbResolver();
|
||||
|
||||
// Get user from database based on HTTP-Signature keyId
|
||||
let authUser = await dbResolver.getAuthUserFromKeyId(signature.keyId);
|
||||
|
||||
// If keyid is unknown, try resolving it
|
||||
if (authUser == null) {
|
||||
try {
|
||||
keyId.hash = '';
|
||||
authUser = await dbResolver.getAuthUserFromApId(getApId(keyId.toString()));
|
||||
} catch (e) {
|
||||
return 403;
|
||||
}
|
||||
}
|
||||
|
||||
if (authUser?.key == null) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
if (authUser.user.host !== host) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
// HTTP-Signature validation
|
||||
const httpSignatureValidated = httpSignature.verifySignature(signature, authUser.key.keyPem);
|
||||
|
||||
if (!httpSignatureValidated) {
|
||||
return 403;
|
||||
}
|
||||
}
|
||||
return 200;
|
||||
}
|
|
@ -13,8 +13,10 @@ export const renderLike = async (noteReaction: NoteReaction, note: Note) => {
|
|||
id: `${config.url}/likes/${noteReaction.id}`,
|
||||
actor: `${config.url}/users/${noteReaction.userId}`,
|
||||
object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`,
|
||||
content: reaction,
|
||||
_misskey_reaction: reaction,
|
||||
... (reaction !== '\u2b50' ? {
|
||||
content: reaction,
|
||||
_misskey_reaction: reaction,
|
||||
} : {}),
|
||||
} as any;
|
||||
|
||||
if (reaction.startsWith(':')) {
|
||||
|
|
|
@ -80,7 +80,11 @@ export default class Resolver {
|
|||
throw new Error('Instance is blocked');
|
||||
}
|
||||
|
||||
if (!this.user) {
|
||||
if (meta.privateMode && config.host !== host && !meta.allowedHosts.includes(host)) {
|
||||
throw new Error('Instance is not allowed');
|
||||
}
|
||||
|
||||
if (config.signToActivityPubGet && !this.user) {
|
||||
this.user = await getInstanceActor();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,14 @@ import renderKey from '@/remote/activitypub/renderer/key.js';
|
|||
import { renderPerson } from '@/remote/activitypub/renderer/person.js';
|
||||
import renderEmoji from '@/remote/activitypub/renderer/emoji.js';
|
||||
import { inbox as processInbox } from '@/queue/index.js';
|
||||
import { isSelfHost } from '@/misc/convert-host.js';
|
||||
import { isSelfHost, toPuny } from '@/misc/convert-host.js';
|
||||
import { Notes, Users, Emojis, NoteReactions } from '@/models/index.js';
|
||||
import { ILocalUser, User } from '@/models/entities/user.js';
|
||||
import { renderLike } from '@/remote/activitypub/renderer/like.js';
|
||||
import { getUserKeypair } from '@/misc/keypair-store.js';
|
||||
import checkFetch from '@/remote/activitypub/check-fetch.js';
|
||||
import { getInstanceActor } from '@/services/instance-actor.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import renderFollow from '@/remote/activitypub/renderer/follow.js';
|
||||
import Outbox, { packActivity } from './activitypub/outbox.js';
|
||||
import Followers from './activitypub/followers.js';
|
||||
|
@ -66,6 +69,12 @@ router.post('/users/:user/inbox', json(), inbox);
|
|||
router.get('/notes/:note', async (ctx, next) => {
|
||||
if (!isActivityPubReq(ctx)) return await next();
|
||||
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const note = await Notes.findOneBy({
|
||||
id: ctx.params.note,
|
||||
visibility: In(['public' as const, 'home' as const]),
|
||||
|
@ -78,7 +87,7 @@ router.get('/notes/:note', async (ctx, next) => {
|
|||
}
|
||||
|
||||
// redirect if remote
|
||||
if (note.userHost != null) {
|
||||
if (note.userHost !== null) {
|
||||
if (note.uri == null || isSelfHost(note.userHost)) {
|
||||
ctx.status = 500;
|
||||
return;
|
||||
|
@ -88,7 +97,13 @@ router.get('/notes/:note', async (ctx, next) => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await renderNote(note, false));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
});
|
||||
|
||||
|
@ -103,6 +118,12 @@ router.get('/notes/:note/activity', async ctx => {
|
|||
return;
|
||||
}
|
||||
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const note = await Notes.findOneBy({
|
||||
id: ctx.params.note,
|
||||
userHost: IsNull(),
|
||||
|
@ -116,7 +137,12 @@ router.get('/notes/:note/activity', async ctx => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await packActivity(note));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
});
|
||||
|
||||
|
@ -134,6 +160,20 @@ router.get('/users/:user/collections/featured', Featured);
|
|||
|
||||
// publickey
|
||||
router.get('/users/:user/publickey', async ctx => {
|
||||
const instanceActor = await getInstanceActor();
|
||||
if (ctx.params.user === instanceActor.id) {
|
||||
ctx.body = renderActivity(renderKey(instanceActor, await getUserKeypair(instanceActor.id)));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
setResponseType(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = ctx.params.user;
|
||||
|
||||
const user = await Users.findOneBy({
|
||||
|
@ -150,7 +190,12 @@ router.get('/users/:user/publickey', async ctx => {
|
|||
|
||||
if (Users.isLocalUser(user)) {
|
||||
ctx.body = renderActivity(renderKey(user, keypair));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
} else {
|
||||
ctx.status = 400;
|
||||
|
@ -165,13 +210,30 @@ async function userInfo(ctx: Router.RouterContext, user: User | null): Promise<v
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await renderPerson(user as ILocalUser));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
}
|
||||
|
||||
router.get('/users/:user', async (ctx, next) => {
|
||||
if (!isActivityPubReq(ctx)) return await next();
|
||||
|
||||
const instanceActor = await getInstanceActor();
|
||||
if (ctx.params.user === instanceActor.id) {
|
||||
await userInfo(ctx, instanceActor);
|
||||
return;
|
||||
}
|
||||
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = ctx.params.user;
|
||||
|
||||
const user = await Users.findOneBy({
|
||||
|
@ -186,6 +248,18 @@ router.get('/users/:user', async (ctx, next) => {
|
|||
router.get('/@:user', async (ctx, next) => {
|
||||
if (!isActivityPubReq(ctx)) return await next();
|
||||
|
||||
if (ctx.params.user === 'instance.actor') {
|
||||
const instanceActor = await getInstanceActor();
|
||||
await userInfo(ctx, instanceActor);
|
||||
return;
|
||||
}
|
||||
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const user = await Users.findOneBy({
|
||||
usernameLower: ctx.params.user.toLowerCase(),
|
||||
host: IsNull(),
|
||||
|
@ -195,8 +269,19 @@ router.get('/@:user', async (ctx, next) => {
|
|||
await userInfo(ctx, user);
|
||||
});
|
||||
|
||||
router.get('/actor', async (ctx, next) => {
|
||||
const instanceActor = await getInstanceActor();
|
||||
await userInfo(ctx, instanceActor);
|
||||
});
|
||||
|
||||
// emoji
|
||||
router.get('/emojis/:emoji', async ctx => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify != 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const emoji = await Emojis.findOneBy({
|
||||
host: IsNull(),
|
||||
name: ctx.params.emoji,
|
||||
|
@ -208,12 +293,23 @@ router.get('/emojis/:emoji', async ctx => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await renderEmoji(emoji));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
});
|
||||
|
||||
// like
|
||||
router.get('/likes/:like', async ctx => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const reaction = await NoteReactions.findOneBy({ id: ctx.params.like });
|
||||
|
||||
if (reaction == null) {
|
||||
|
@ -232,12 +328,22 @@ router.get('/likes/:like', async ctx => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(await renderLike(reaction, note));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
});
|
||||
|
||||
// follow
|
||||
router.get('/follows/:follower/:followee', async ctx => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
// This may be used before the follow is completed, so we do not
|
||||
// check if the following exists.
|
||||
|
||||
|
@ -258,7 +364,12 @@ router.get('/follows/:follower/:followee', async ctx => {
|
|||
}
|
||||
|
||||
ctx.body = renderActivity(renderFollow(follower, followee));
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
});
|
||||
|
||||
|
|
|
@ -5,9 +5,20 @@ import { renderActivity } from '@/remote/activitypub/renderer/index.js';
|
|||
import renderOrderedCollection from '@/remote/activitypub/renderer/ordered-collection.js';
|
||||
import renderNote from '@/remote/activitypub/renderer/note.js';
|
||||
import { Users, Notes, UserNotePinings } from '@/models/index.js';
|
||||
import checkFetch from '@/remote/activitypub/check-fetch.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
import { setResponseType } from '../activitypub.js';
|
||||
import { IsNull } from 'typeorm';
|
||||
import checkFetch from '@/remote/activitypub/check-fetch.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
|
||||
export default async (ctx: Router.RouterContext) => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = ctx.params.user;
|
||||
|
||||
const user = await Users.findOneBy({
|
||||
|
@ -36,6 +47,12 @@ export default async (ctx: Router.RouterContext) => {
|
|||
);
|
||||
|
||||
ctx.body = renderActivity(rendered);
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
setResponseType(ctx);
|
||||
};
|
||||
|
|
|
@ -9,12 +9,20 @@ import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js';
|
|||
import { Users, Followings, UserProfiles } from '@/models/index.js';
|
||||
import { Following } from '@/models/entities/following.js';
|
||||
import { setResponseType } from '../activitypub.js';
|
||||
import checkFetch from '@/remote/activitypub/check-fetch.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
|
||||
export default async (ctx: Router.RouterContext) => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = ctx.params.user;
|
||||
|
||||
const cursor = ctx.request.query.cursor;
|
||||
if (cursor != null && typeof cursor !== 'string') {
|
||||
if (cursor !== null && typeof cursor !== 'string') {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
|
@ -89,7 +97,12 @@ export default async (ctx: Router.RouterContext) => {
|
|||
// index page
|
||||
const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`);
|
||||
ctx.body = renderActivity(rendered);
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
setResponseType(ctx);
|
||||
}
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,12 +9,20 @@ import renderFollowUser from '@/remote/activitypub/renderer/follow-user.js';
|
|||
import { Users, Followings, UserProfiles } from '@/models/index.js';
|
||||
import { Following } from '@/models/entities/following.js';
|
||||
import { setResponseType } from '../activitypub.js';
|
||||
import checkFetch from '@/remote/activitypub/check-fetch.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
|
||||
export default async (ctx: Router.RouterContext) => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = ctx.params.user;
|
||||
|
||||
const cursor = ctx.request.query.cursor;
|
||||
if (cursor != null && typeof cursor !== 'string') {
|
||||
if (cursor !== null && typeof cursor !== 'string') {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
|
@ -89,7 +97,12 @@ export default async (ctx: Router.RouterContext) => {
|
|||
// index page
|
||||
const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`);
|
||||
ctx.body = renderActivity(rendered);
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
setResponseType(ctx);
|
||||
}
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,25 +14,33 @@ import { Note } from '@/models/entities/note.js';
|
|||
import { isPureRenote } from '@/misc/renote.js';
|
||||
import { makePaginationQuery } from '../api/common/make-pagination-query.js';
|
||||
import { setResponseType } from '../activitypub.js';
|
||||
import checkFetch from '@/remote/activitypub/check-fetch.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
|
||||
export default async (ctx: Router.RouterContext) => {
|
||||
const verify = await checkFetch(ctx.req);
|
||||
if (verify !== 200) {
|
||||
ctx.status = verify;
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = ctx.params.user;
|
||||
|
||||
const sinceId = ctx.request.query.since_id;
|
||||
if (sinceId != null && typeof sinceId !== 'string') {
|
||||
if (sinceId !== null && typeof sinceId !== 'string') {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
const untilId = ctx.request.query.until_id;
|
||||
if (untilId != null && typeof untilId !== 'string') {
|
||||
if (untilId !== null && typeof untilId !== 'string') {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
const page = ctx.request.query.page === 'true';
|
||||
|
||||
if (countIf(x => x != null, [sinceId, untilId]) > 1) {
|
||||
if (countIf(x => x !== null, [sinceId, untilId]) > 1) {
|
||||
ctx.status = 400;
|
||||
return;
|
||||
}
|
||||
|
@ -90,9 +98,15 @@ export default async (ctx: Router.RouterContext) => {
|
|||
`${partOf}?page=true&since_id=000000000000000000000000`,
|
||||
);
|
||||
ctx.body = renderActivity(rendered);
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
|
||||
setResponseType(ctx);
|
||||
}
|
||||
const meta = await fetchMeta();
|
||||
if (meta.secureMode || meta.privateMode) {
|
||||
ctx.set('Cache-Control', 'no-store');
|
||||
} else {
|
||||
ctx.set('Cache-Control', 'public, max-age=180');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,8 @@ import { limiter } from './limiter.js';
|
|||
import endpoints, { IEndpointMeta } from './endpoints.js';
|
||||
import { ApiError } from './error.js';
|
||||
import { apiLogger } from './logger.js';
|
||||
import { AccessToken } from '@/models/entities/access-token.js';
|
||||
import { fetchMeta } from '@/misc/fetch-meta.js';
|
||||
|
||||
export default async (endpoint: string, user: CacheableLocalUser | null | undefined, token: AccessToken | null | undefined, data: any, ctx?: Koa.Context) => {
|
||||
const isSecure = user != null && token == null;
|
||||
|
@ -61,6 +63,17 @@ export default async (endpoint: string, user: CacheableLocalUser | null | undefi
|
|||
throw new ApiError('ACCESS_DENIED', 'This operation requires privileges which this token does not grant.');
|
||||
}
|
||||
|
||||
// private mode
|
||||
const meta = await fetchMeta();
|
||||
if (meta.privateMode && ep.meta.requireCredentialPrivateMode && user == null) {
|
||||
throw new ApiError({
|
||||
message: 'Credential required.',
|
||||
code: 'CREDENTIAL_REQUIRED',
|
||||
id: '1384574d-a912-4b81-8601-c7b1c4085df1',
|
||||
httpStatusCode: 401
|
||||
});
|
||||
}
|
||||
|
||||
// Cast non JSON input
|
||||
if ((ep.meta.requireFile || ctx?.method === 'GET') && ep.params.properties) {
|
||||
for (const k of Object.keys(ep.params.properties)) {
|
||||
|
|
|
@ -683,6 +683,12 @@ export interface IEndpointMeta {
|
|||
*/
|
||||
readonly secure?: boolean;
|
||||
|
||||
/**
|
||||
* If in private mode, whether credentials are required when making a request to this endpoint.
|
||||
* If omitted, this is interpreted as false.
|
||||
*/
|
||||
readonly requireCredentialPrivateMode?: boolean;
|
||||
|
||||
/**
|
||||
* エンドポイントの種類
|
||||
* パーミッションの実現に利用されます。
|
||||
|
|
|
@ -102,18 +102,6 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableTwitterIntegration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableGithubIntegration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableDiscordIntegration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
translatorAvailable: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
@ -150,6 +138,22 @@ export const meta = {
|
|||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
allowedHosts: {
|
||||
type: 'array',
|
||||
optional: true, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
privateMode: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
secureMode: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
hcaptchaSecretKey: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
|
@ -163,30 +167,6 @@ export const meta = {
|
|||
optional: true, nullable: true,
|
||||
format: 'id',
|
||||
},
|
||||
twitterConsumerKey: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
twitterConsumerSecret: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
githubClientId: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
githubClientSecret: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
discordClientId: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
discordClientSecret: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
},
|
||||
summaryProxy: {
|
||||
type: 'string',
|
||||
optional: true, nullable: true,
|
||||
|
@ -335,15 +315,12 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
pinnedUsers: instance.pinnedUsers,
|
||||
hiddenTags: instance.hiddenTags,
|
||||
blockedHosts: instance.blockedHosts,
|
||||
allowedHosts: instance.allowedHosts,
|
||||
privateMode: instance.privateMode,
|
||||
secureMode: instance.secureMode,
|
||||
hcaptchaSecretKey: instance.hcaptchaSecretKey,
|
||||
recaptchaSecretKey: instance.recaptchaSecretKey,
|
||||
proxyAccountId: instance.proxyAccountId,
|
||||
twitterConsumerKey: instance.twitterConsumerKey,
|
||||
twitterConsumerSecret: instance.twitterConsumerSecret,
|
||||
githubClientId: instance.githubClientId,
|
||||
githubClientSecret: instance.githubClientSecret,
|
||||
discordClientId: instance.discordClientId,
|
||||
discordClientSecret: instance.discordClientSecret,
|
||||
summalyProxy: instance.summalyProxy,
|
||||
email: instance.email,
|
||||
smtpSecure: instance.smtpSecure,
|
||||
|
|
|
@ -26,6 +26,11 @@ export const paramDef = {
|
|||
blockedHosts: { type: 'array', nullable: true, items: {
|
||||
type: 'string',
|
||||
} },
|
||||
allowedHosts: { type: 'array', nullable: true, items: {
|
||||
type: 'string',
|
||||
} },
|
||||
secureMode: { type: 'boolean', nullable: true },
|
||||
privateMode: { type: 'boolean', nullable: true },
|
||||
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
|
||||
bannerUrl: { type: 'string', nullable: true },
|
||||
iconUrl: { type: 'string', nullable: true },
|
||||
|
@ -60,15 +65,6 @@ export const paramDef = {
|
|||
deeplAuthKey: { type: 'string', nullable: true },
|
||||
libreTranslateAuthKey: { type: 'string', nullable: true },
|
||||
libreTranslateEndpoint: { type: 'string', nullable: true },
|
||||
enableTwitterIntegration: { type: 'boolean' },
|
||||
twitterConsumerKey: { type: 'string', nullable: true },
|
||||
twitterConsumerSecret: { type: 'string', nullable: true },
|
||||
enableGithubIntegration: { type: 'boolean' },
|
||||
githubClientId: { type: 'string', nullable: true },
|
||||
githubClientSecret: { type: 'string', nullable: true },
|
||||
enableDiscordIntegration: { type: 'boolean' },
|
||||
discordClientId: { type: 'string', nullable: true },
|
||||
discordClientSecret: { type: 'string', nullable: true },
|
||||
enableEmail: { type: 'boolean' },
|
||||
email: { type: 'string', nullable: true },
|
||||
smtpSecure: { type: 'boolean' },
|
||||
|
@ -130,6 +126,18 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.themeColor = ps.themeColor;
|
||||
}
|
||||
|
||||
if (Array.isArray(ps.allowedHosts)) {
|
||||
set.allowedHosts = ps.allowedHosts.filter(Boolean);
|
||||
}
|
||||
|
||||
if (typeof ps.privateMode === 'boolean') {
|
||||
set.privateMode = ps.privateMode;
|
||||
}
|
||||
|
||||
if (typeof ps.secureMode === 'boolean') {
|
||||
set.secureMode = ps.secureMode;
|
||||
}
|
||||
|
||||
if (ps.bannerUrl !== undefined) {
|
||||
set.bannerUrl = ps.bannerUrl;
|
||||
}
|
||||
|
@ -230,42 +238,6 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
set.summalyProxy = ps.summalyProxy;
|
||||
}
|
||||
|
||||
if (ps.enableTwitterIntegration !== undefined) {
|
||||
set.enableTwitterIntegration = ps.enableTwitterIntegration;
|
||||
}
|
||||
|
||||
if (ps.twitterConsumerKey !== undefined) {
|
||||
set.twitterConsumerKey = ps.twitterConsumerKey;
|
||||
}
|
||||
|
||||
if (ps.twitterConsumerSecret !== undefined) {
|
||||
set.twitterConsumerSecret = ps.twitterConsumerSecret;
|
||||
}
|
||||
|
||||
if (ps.enableGithubIntegration !== undefined) {
|
||||
set.enableGithubIntegration = ps.enableGithubIntegration;
|
||||
}
|
||||
|
||||
if (ps.githubClientId !== undefined) {
|
||||
set.githubClientId = ps.githubClientId;
|
||||
}
|
||||
|
||||
if (ps.githubClientSecret !== undefined) {
|
||||
set.githubClientSecret = ps.githubClientSecret;
|
||||
}
|
||||
|
||||
if (ps.enableDiscordIntegration !== undefined) {
|
||||
set.enableDiscordIntegration = ps.enableDiscordIntegration;
|
||||
}
|
||||
|
||||
if (ps.discordClientId !== undefined) {
|
||||
set.discordClientId = ps.discordClientId;
|
||||
}
|
||||
|
||||
if (ps.discordClientSecret !== undefined) {
|
||||
set.discordClientSecret = ps.discordClientSecret;
|
||||
}
|
||||
|
||||
if (ps.enableEmail !== undefined) {
|
||||
set.enableEmail = ps.enableEmail;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['meta'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -5,6 +5,7 @@ export const meta = {
|
|||
tags: ['channels'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['channels'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['notes', 'channels'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'users'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(activeUsersChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(apRequestChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'drive'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(driveChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(federationChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'hashtags'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(hashtagChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(instanceChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'notes'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(notesChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'drive', 'users'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserDriveChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'users', 'following'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserFollowingChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'users', 'notes'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserNotesChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'users', 'reactions'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(perUserReactionsChart.schema),
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['charts', 'users'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: getJsonSchema(usersChart.schema),
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ export const meta = {
|
|||
tags: ['account', 'notes', 'clips'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
kind: 'read:account',
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['clips', 'account'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
kind: 'read:account',
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['federation'],
|
||||
|
||||
requireCredential: true,
|
||||
requireCredentialPrivateMode: true,
|
||||
requireAdmin: true,
|
||||
|
||||
res: {
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['federation'],
|
||||
|
||||
requireCredential: true,
|
||||
requireCredentialPrivateMode: true,
|
||||
requireAdmin: true,
|
||||
|
||||
res: {
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['federation'],
|
||||
|
||||
requireCredential: true,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['federation'],
|
||||
|
||||
requireCredential: true,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
oneOf: [{
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['federation'],
|
||||
|
||||
requireCredential: true,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['gallery'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -5,6 +5,7 @@ export const meta = {
|
|||
tags: ['gallery'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['gallery'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -6,6 +6,7 @@ export const meta = {
|
|||
tags: ['gallery'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
errors: ['NO_SUCH_POST'],
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ export const meta = {
|
|||
tags: ['meta'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
|
|
@ -5,6 +5,7 @@ export const meta = {
|
|||
tags: ['hashtags'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -5,6 +5,7 @@ export const meta = {
|
|||
tags: ['hashtags'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const meta = {
|
|||
tags: ['hashtags'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
|
|
|
@ -25,6 +25,7 @@ export const meta = {
|
|||
tags: ['hashtags'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -5,6 +5,7 @@ import define from '../../define.js';
|
|||
|
||||
export const meta = {
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
tags: ['hashtags', 'users'],
|
||||
|
||||
|
|
|
@ -170,18 +170,6 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableTwitterIntegration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableGithubIntegration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableDiscordIntegration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
translatorAvailable: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
@ -222,18 +210,6 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
twitter: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
github: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
discord: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
serviceWorker: {
|
||||
type: 'boolean',
|
||||
optional: true, nullable: false,
|
||||
|
@ -246,6 +222,16 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
},
|
||||
secureMode: {
|
||||
type: 'boolean',
|
||||
optional: true, nullable: false,
|
||||
default: false,
|
||||
},
|
||||
privateMode: {
|
||||
type: 'boolean',
|
||||
optional: true, nullable: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
@ -264,7 +250,7 @@ export const paramDef = {
|
|||
} as const;
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default define(meta, paramDef, async (ps, me) => {
|
||||
export default define(meta, paramDef, async (ps, me): Promise<Record<string, any>> => {
|
||||
const instance = await fetchMeta(true);
|
||||
|
||||
const emojis = await Emojis.find({
|
||||
|
@ -281,7 +267,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
},
|
||||
});
|
||||
|
||||
return {
|
||||
const response: Record<string, any> = {
|
||||
maintainerName: instance.maintainerName,
|
||||
maintainerEmail: instance.maintainerEmail,
|
||||
|
||||
|
@ -292,6 +278,10 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
description: instance.description,
|
||||
langs: instance.langs,
|
||||
tosUrl: instance.ToSUrl,
|
||||
|
||||
secureMode: instance.secureMode,
|
||||
privateMode: instance.privateMode,
|
||||
|
||||
disableRegistration: instance.disableRegistration,
|
||||
disableLocalTimeline: instance.disableLocalTimeline,
|
||||
disableGlobalTimeline: instance.disableGlobalTimeline,
|
||||
|
@ -309,27 +299,30 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
backgroundImageUrl: instance.backgroundImageUrl,
|
||||
logoImageUrl: instance.logoImageUrl,
|
||||
maxNoteTextLength: config.maxNoteTextLength,
|
||||
emojis: await Emojis.packMany(emojis),
|
||||
emojis: instance.privateMode && !me ? [] : await Emojis.packMany(emojis),
|
||||
defaultLightTheme: instance.defaultLightTheme,
|
||||
defaultDarkTheme: instance.defaultDarkTheme,
|
||||
enableEmail: instance.enableEmail,
|
||||
|
||||
enableTwitterIntegration: instance.enableTwitterIntegration,
|
||||
enableGithubIntegration: instance.enableGithubIntegration,
|
||||
enableDiscordIntegration: instance.enableDiscordIntegration,
|
||||
|
||||
translatorAvailable: translatorAvailable(instance),
|
||||
|
||||
pinnedPages: instance.pinnedPages,
|
||||
pinnedClipId: instance.pinnedClipId,
|
||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||
requireSetup: (await Users.countBy({
|
||||
host: IsNull(),
|
||||
})) === 0,
|
||||
...(ps.detail ? {
|
||||
pinnedPages: instance.privateMode && !me ? [] : instance.pinnedPages,
|
||||
pinnedClipId: instance.privateMode && !me ? [] : instance.pinnedClipId,
|
||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||
requireSetup: (await Users.countBy({
|
||||
host: IsNull(),
|
||||
})) === 0,
|
||||
} : {}),
|
||||
};
|
||||
|
||||
proxyAccountName: instance.proxyAccountId ? (await Users.pack(instance.proxyAccountId).catch(() => null))?.username : null,
|
||||
|
||||
features: {
|
||||
if (ps.detail) {
|
||||
if (!instance.privateMode || me) {
|
||||
const proxyAccount = instance.proxyAccountId ? await Users.pack(instance.proxyAccountId).catch(() => null) : null;
|
||||
response.proxyAccountName = proxyAccount ? proxyAccount.username : null;
|
||||
}
|
||||
response.features = {
|
||||
registration: !instance.disableRegistration,
|
||||
localTimeLine: !instance.disableLocalTimeline,
|
||||
globalTimeLine: !instance.disableGlobalTimeline,
|
||||
|
@ -338,11 +331,10 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
hcaptcha: instance.enableHcaptcha,
|
||||
recaptcha: instance.enableRecaptcha,
|
||||
objectStorage: instance.useObjectStorage,
|
||||
twitter: instance.enableTwitterIntegration,
|
||||
github: instance.enableGithubIntegration,
|
||||
discord: instance.enableDiscordIntegration,
|
||||
serviceWorker: true,
|
||||
miauth: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
return response;
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ import { makePaginationQuery } from '../common/make-pagination-query.js';
|
|||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredentialPrivateMode: true,
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
@ -9,6 +9,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Get a list of children of a notes. Children includes replies as well as quote renotes that quote the respective post. A post will not be duplicated if it is a reply and a quote of a note in this thread. For depths larger than 1 the threading has to be computed by the client.',
|
||||
|
||||
|
@ -21,7 +22,7 @@ export const meta = {
|
|||
ref: 'Note',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['clips', 'notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -13,6 +13,7 @@ import { generateMutedRenotesQuery } from '../../common/generated-muted-renote-q
|
|||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredentialPrivateMode: true,
|
||||
res: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
@ -15,6 +15,7 @@ import { generateMutedRenotesQuery } from '../../common/generated-muted-renote-q
|
|||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -9,6 +9,7 @@ export const meta = {
|
|||
tags: ['notes', 'reactions'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
allowGet: true,
|
||||
cacheSec: 60,
|
||||
|
|
|
@ -11,6 +11,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -9,6 +9,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -10,6 +10,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['notes', 'hashtags'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -12,6 +12,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -7,6 +7,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
|
|
|
@ -43,6 +43,7 @@ export const meta = {
|
|||
tags: ['notes'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
|
|
|
@ -5,6 +5,7 @@ export const meta = {
|
|||
tags: ['pages'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['pages'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
|
|
|
@ -9,6 +9,7 @@ export const meta = {
|
|||
tags: ['users'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../define.js';
|
|||
|
||||
export const meta = {
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
tags: ['meta'],
|
||||
} as const;
|
||||
|
|
|
@ -4,6 +4,7 @@ import define from '../define.js';
|
|||
|
||||
export const meta = {
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
tags: ['meta'],
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['users'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['users', 'clips'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Show all clips this user owns.',
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ export const meta = {
|
|||
tags: ['users'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Show everyone that follows this user.',
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ export const meta = {
|
|||
tags: ['users'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Show everyone that this user is following.',
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../../common/make-pagination-query.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['users', 'gallery'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Show all gallery posts by the given user.',
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import { generateBlockedUserQuery } from '../../common/generate-block-query.js';
|
|||
export const meta = {
|
||||
tags: ['users', 'notes'],
|
||||
|
||||
requireCredentialPrivateMode: true,
|
||||
description: 'Show all notes that this user created.',
|
||||
|
||||
res: {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { makePaginationQuery } from '../../common/make-pagination-query.js';
|
|||
|
||||
export const meta = {
|
||||
tags: ['users', 'pages'],
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Show all pages this user created.',
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ export const meta = {
|
|||
tags: ['users', 'reactions'],
|
||||
|
||||
requireCredential: false,
|
||||
requireCredentialPrivateMode: true,
|
||||
|
||||
description: 'Show all reactions this user made.',
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue