Compare commits
21 commits
7c93e1a91a
...
43708ead38
Author | SHA1 | Date | |
---|---|---|---|
43708ead38 | |||
ce7a95796c | |||
09b76b4a13 | |||
c4c9041222 | |||
e35ae0846d | |||
f8d04eafa4 | |||
ed6d506bc2 | |||
df2989bade | |||
fb8a8614f4 | |||
d6dd6ff897 | |||
0d8ee4387b | |||
c1e0186e7b | |||
15dabfc878 | |||
595fe24471 | |||
825eef74aa | |||
fcccf2eb29 | |||
d8ffcf8c51 | |||
6bfe6066db | |||
4e63873fc1 | |||
26cd2a68da | |||
69cf9b42e0 |
99 changed files with 1472 additions and 916 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -28,10 +28,7 @@ coverage
|
|||
!/.config/docker_ci.env
|
||||
!/.config/helm_values_example.yml
|
||||
!/.config/LICENSE
|
||||
docker-compose.yml
|
||||
|
||||
# docker dev config
|
||||
/dev/docker-compose.yml
|
||||
/docker-compose.yml
|
||||
|
||||
# ESLint
|
||||
.eslintcache
|
||||
|
|
48
Makefile
48
Makefile
|
@ -1,19 +1,49 @@
|
|||
.PHONY: all
|
||||
all: shellcheck build_image
|
||||
.PHONY: build
|
||||
build: build-image
|
||||
|
||||
|
||||
.PHONY: pre-commit
|
||||
pre-commit: shellcheck rust-lint regenerate-entities update-index-js
|
||||
|
||||
|
||||
.PHONY: debug
|
||||
debug:
|
||||
pnpm install
|
||||
pnpm run build:debug
|
||||
pnpm run migrate
|
||||
pnpm run start
|
||||
|
||||
|
||||
.PHONY: shellcheck
|
||||
shellcheck:
|
||||
shellcheck --external-sources update.sh
|
||||
shellcheck --external-sources neko/update/main.sh
|
||||
shellcheck --external-sources neko/update/patch.sh
|
||||
shellcheck --external-sources neko/update/container.sh
|
||||
shellcheck --external-sources neko/update/native.sh
|
||||
shellcheck --external-sources --exclude=SC2148 neko/update/utils
|
||||
shellcheck --external-sources neko/update/*
|
||||
|
||||
|
||||
.PHONY: build_image
|
||||
build_image:
|
||||
.PHONY: rust-lint
|
||||
rust-lint:
|
||||
cd packages/backend/native-utils && pnpm run lint
|
||||
|
||||
|
||||
.PHONY: regenerate-entities
|
||||
regenerate-entities:
|
||||
cd packages/backend/native-utils && \
|
||||
sea-orm-cli generate entity \
|
||||
--output-dir='src/model/entity' \
|
||||
--database-url='postgres://firefish:password@localhost/firefish_db'
|
||||
|
||||
|
||||
.PHONY: update-index-js
|
||||
update-index-js:
|
||||
pnpm --filter='native-utils' run build:debug
|
||||
[ -f packages/backend/native-utils/built/index.js ]
|
||||
pnpm run format
|
||||
rm neko/index.js
|
||||
cp packages/backend/native-utils/built/index.js neko/index.js
|
||||
|
||||
|
||||
.PHONY: build-image
|
||||
build-image:
|
||||
. neko/update/utils && \
|
||||
buildah build \
|
||||
--no-cache \
|
||||
|
|
647
README.md
647
README.md
|
@ -1,641 +1,16 @@
|
|||
[Misskey](https://misskey-hub.net/) のフォークの [Firefish](https://joinfirefish.org/) のフォークです。
|
||||
# Firefish
|
||||
|
||||
本家 Firefish のリポジトリは[こちら](https://git.joinfirefish.org/firefish/firefish)
|
||||
[Misskey](https://misskey-hub.net/) のハードフォークの [Firefish](https://joinfirefish.org/) のソフトフォークです。[私](https://post.naskya.net/@dev)が個人的に使うことが主な目的ですから、これを使うことを積極的におすすめすることはありません。しかし労力を掛けて作ったものを一人占めするのももったいないので、使いたかったら使ってもいいよ、という気持ちで公開しています。
|
||||
|
||||
`main` ブランチではこのフォークに適用された変更のコミット履歴のみが、`history` ブランチでは本家 Firefish のコミットを含む完全なコミット履歴が閲覧できます。
|
||||
本家 Firefish のリポジトリは[こちら](https://git.joinfirefish.org/firefish/firefish)です。
|
||||
|
||||
このフォークの機能について調べるには `main` ブランチを、コードの著者について調べるには `history` ブランチを参照してください。
|
||||
`main` ブランチではこのフォークに適用された変更のコミット履歴のみが、`history` ブランチでは Misskey の最初のコミットから始まる完全なコミット履歴を確認できます。このフォークの機能について調べるには `main` ブランチを、コードの著者について調べるには `history` ブランチを参照してください。
|
||||
|
||||
# 変更点
|
||||
## 各種説明
|
||||
|
||||
## 主要な変更点
|
||||
|
||||
- 非ログインユーザーにもローカルタイムラインとグローバルタイムラインを公開できるように変更
|
||||
- コントロールパネルから設定すると `https://server.example.com/timeline` で公開されます
|
||||
- 検索フィルターを強化
|
||||
- 以下の機能があります
|
||||
- AND 検索
|
||||
- OR 検索
|
||||
- 自分の(未収載・フォロワー限定・ダイレクト・秘密を含む)全ての投稿からの検索
|
||||
- 特定のユーザーの投稿の検索
|
||||
- 特定のサーバーの投稿の検索
|
||||
- 特定の期間の投稿の検索
|
||||
- 添付ファイル付きの投稿の検索
|
||||
- 全文検索のエンジンを [PGroonga](https://pgroonga.github.io/) に変更
|
||||
- PGroonga のインストールが必要になります!詳しくは[この投稿](https://post.naskya.net/notes/9ldi29amfanomef5)をご覧ください
|
||||
- Meilisearch, Elasticsearch, Sonic は使えません
|
||||
- 「秘密」という公開範囲を追加
|
||||
- 宛先無しのダイレクト投稿を言い換えているだけです
|
||||
- 既存の投稿を削除せずに後から秘密にすることもできます
|
||||
- パフォーマンス向上のためアクティブユーザー以外のチャート生成を無効化
|
||||
- サードパーティー製クライアントが動かなくなるのを阻止するため API のエンドポイントは残していますが、叩いても `0` が並んだ配列しか返しません。
|
||||
- モデレーターでない一般ユーザーにもカスタム絵文字の管理権を与えられるように
|
||||
- カスタム絵文字の管理が大変なサーバー管理者さんがたくさんいらっしゃったのでこの機能を追加するべきではないか他の開発者に訊いたところロール機能の実装を待つべきだと言われてしまったが、Firefish のロール機能は現状では仕様がまだ固まっておらず実装までに時間が掛かると考えられるため
|
||||
- 以下の権限を与えられます
|
||||
- 不許可: 絵文字の管理を許可しない
|
||||
- 追加: 新しい絵文字の追加のみを許可する
|
||||
- 追加と変更: 「追加」に加え、既存のカスタム絵文字の名前・カテゴリ・タグ・ライセンスの編集を許可する
|
||||
- 全て許可:「追加と変更」に加え、既存のカスタム絵文字の削除を許可する
|
||||
- モバイル表示の下部のウィジェットボタンを再読み込みボタンに変更可能に
|
||||
- スマートフォンでウィジェットは使わないけど再読み込みはたくさんする人はいそう
|
||||
- モバイル表示の下部のチャットボタンをアカウント切り替えボタンに変更可能に
|
||||
- これ無しで PWA で複数アカウントを使おうとすると腱鞘炎になる
|
||||
- ローカルタイムラインの位置をグローバルタイムラインの直前に移動
|
||||
- ローカルタイムラインよりもソーシャルタイムラインのほうが使いやすいと考えたため
|
||||
|
||||
## 細かい変更点
|
||||
|
||||
- 猫語で "nA" を "nYA" に置換しない
|
||||
- この置き換えはあまり嬉しくないことが多い
|
||||
- `reset-db` という API を無効化
|
||||
- エンドポイント自体は残してありますが、叩いても何もしません
|
||||
- データベースをリセットする API って何?怖すぎる
|
||||
- ユーザーページでプロフィール画像を選択すると画像を拡大する(Catodon から取り込み)
|
||||
- 署名アルゴリズムとして ECDSA や Ed25519 なども受け入れる([github.com/mei23/misskey-v12](https://github.com/mei23/misskey-v12) から取り込み)
|
||||
- Pleroma のチャットに対応(Catodon から取り込み)
|
||||
- 翻訳機能にて、投稿言語が指定されていない場合にのみ言語の自動検出を用いるように変更
|
||||
- アップデート時に更新内容を確認できる機能を追加
|
||||
- 依存ライブラリを最新版にアップデート
|
||||
- ちゃんと動くか本家に push する前に実験したいという意図もあります
|
||||
- 中国語の猫モードでは 0.1 の確率で投稿の末尾に「喵」を追加するように
|
||||
- 設定のバックアップファイルに `misskeyVersion` の値が含まれていなくても警告しないように変更
|
||||
- マージされていない本家版へのプルリクエストを独断でマージ
|
||||
- RTL Layout Support ([!10452](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10452))
|
||||
- Add language picker to post form ([!10616](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10616))
|
||||
- chore: up swc ([!10649](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10649))
|
||||
- `emojis` の API エンドポイント(Misskey v13- 互換)を追加([firefish-mkdir](https://git.mkdir.uk/hiira/firefish-mkdir) から取り込み)
|
||||
- Docker のベースイメージに Node v21 を使用
|
||||
- HTML のコードに入るコメントアートを削除
|
||||
- 全ページにこんなの入れなくても……
|
||||
- デフォルトではバイブレーションを無効に
|
||||
- ログインしていなければ投稿検索ができないように
|
||||
- 攻撃対策のため
|
||||
- もしこのせいでサードパーティークライアントに不具合が出る場合には変更するかもしれません
|
||||
- 投稿と投稿の間を空けて表示する設定をデフォルトでは無効に
|
||||
- Enter キーのみでチャットを送信する設定をデフォルトでは無効に
|
||||
- 管理者アカウントも引っ越しできるように
|
||||
- デフォルトのアイコンの太さを細めに変更
|
||||
- スタイルを選択する画面のサンプルのアイコンを星に変更
|
||||
- リアクションの履歴を公開する設定をデフォルトで有効に
|
||||
- 私がみんなのリアクションを見たいと思っているため
|
||||
- もちろん設定から無効にできます
|
||||
- 標準のフォントを Atkinson Hyperlegible にする変更を取り消し
|
||||
- フォントを変更したい場合は[このカスタム CSS](https://gitlab.com/LunarEclipse363/lunar-misskey-tweaks#setting-a-different-font) を使ってください
|
||||
- 簡体中文の翻訳が存在しない項目では繁体中文の翻訳を用いるように(本家では逆)
|
||||
- [サポミク](https://fedi.sup39.dev/@sup39)さんが独自機能に使われているラベルの繁体中文訳を提供してくださったため
|
||||
- オンラインステータスが非公開のアカウントにはステータスを表す丸印を表示しないように
|
||||
- 灰色の丸が表示されていてもそんなに嬉しくないため
|
||||
- デフォルトで検索エンジンからのクロールを拒否するように変更
|
||||
- 検索の MFM で使用する検索エンジンを設定から変更可能に
|
||||
- 以下の選択肢から選べます
|
||||
- DuckDuckGo (duckduckgo.com)
|
||||
- SearXNG (searx.be)
|
||||
- Google Search (google.com)
|
||||
- Moon Search (search.naskya.net)
|
||||
- サーバーの投稿検索
|
||||
- サーバー設定の初期値を変更
|
||||
- 新規登録を無効化
|
||||
- 新規登録を受け付けたくないのに無効化する前にアカウントを登録されてしまうことを防ぐため
|
||||
- プライベートモード(連合しないモード)を有効化
|
||||
- サーバーの準備が整っていないうちにリモートサーバーに認識されてしまうことを防ぐため
|
||||
- サーバーメトリクスの表示を有効化
|
||||
- 有効化しているサーバーが多いため
|
||||
- ランダムなアイコンの生成を無効化
|
||||
- ランダムなアイコンはそんなにかわいくないため
|
||||
- 身バレ防止の設定を追加
|
||||
- 「おかえりなさい、◯◯さん」が出ないようにできるように
|
||||
- 自分のアイコンを非表示にできるように
|
||||
- 自分の名前とIDを非表示にできるように
|
||||
- 名前とIDの部分が空白になるので慣れるまで時間が掛かります
|
||||
- ユーザーページのデフォルトのタブを「投稿と返信」に変更
|
||||
- タイムラインにリプライを表示する設定をデフォルトで有効に
|
||||
- 未読通知のタブをリアクションの通知を表示するタブに変更
|
||||
- 未読のタブ、使ってる人いる?
|
||||
- MFM チートシートのボタンを投稿画面から左下のヘルプメニューに移動
|
||||
- これがあるために投稿画面下部のボタンが 2 段になってしまうことがあるため
|
||||
- 「フォローされています」の表示を目立たせられるように
|
||||
- デフォルトの表示は目立たないため
|
||||
- 最大 15 件の投稿を固定できるように
|
||||
- 5 件は少ないと思ったため
|
||||
- 投稿ボタンを巨大にできるように
|
||||
- [mstdn.maud.io / mstdn.poyo.me の機能](https://mstdn.poyo.me/@prime/110668364208741253) を真似しました
|
||||
- アンテナにフォロー中のユーザーのホーム投稿も表示する
|
||||
- フォロー中のユーザーの投稿は見たいから
|
||||
- 猫のアカウントはアイコンを常に丸く表示する
|
||||
- そのほうがかわいいため
|
||||
- NSFW メディアを隠す設定をブラウザごとの設定からブラウザごとかつアカウントごとの設定に変更
|
||||
- 「このアカウントでは NSFW の画像を常に表示したい」みたいな需要が私にあったため
|
||||
- インスタンスティッカーをデフォルトで常に表示する
|
||||
- そのほうが楽しいと思ったから
|
||||
- 藍ちゃんウィジェットの復活
|
||||
- インスタンスティッカーのツールチップにソフトウェアのバージョン番号も表示する
|
||||
- 気になるから
|
||||
- いいねボタン(リアクションピッカーの左にある、⭐とか👍のリアクションをワンクリックで押せるやつ)で空のリアクション(Mastodon がふぁぼで送ってくるものと同じ)ではなく本当にその絵文字リアクション(⭐とか👍とか)を送るようにする
|
||||
- 最新の Misskey ではデフォルトリアクションが❤️になったため空のリアクションを送ると❤️として表示されてしまうが、❤️は ℒℴ𝓋ℯ... という気持ちを伝えるためのリアクションであってただの「いいね」とは異なるため、このボタンで❤️は送りたくないから
|
||||
- 通知の表示を簡潔にする
|
||||
- 「がリアクションしました」とかリプライの上にある白い線とかが邪魔に思えたため
|
||||
- 一部の表示の色も Misskey の通知の色が個人的に好みだったので戻した
|
||||
- 支援者リストをファイルから読み込む
|
||||
- 外部のサーバーが落ちるとユーザーページが開けなくなることを防ぐため
|
||||
- 閲覧注意の注釈と画像の代替テキストもアンテナで調べる対象にする
|
||||
- ~~「そぎぎ」でアンテナを作れる~~
|
||||
- インデックス拒否に `noindex` に加えて `nofollow,noarchive,nocache,noimageindex` も指定
|
||||
- インスタンスティッカーに表示するサーバーのアイコンとして favicon を優先する
|
||||
- favicon のほうがよくカスタマイズされているため
|
||||
- 誤爆しやすい位置にあるフォローボタンを隠す設定を追加
|
||||
- フォローを誤爆すると悲しいため
|
||||
- デフォルトの robots.txt の設定を変更し、クローラーを拒否するように
|
||||
- joinfirefish と FediDB のクローラーは許可しています
|
||||
- 投稿プレビューをデフォルトでオンにする設定を追加
|
||||
- バージョン番号に最新のコミットの日付とコミットハッシュの頭文字が含まれるように
|
||||
- 正確なバージョンが分かるとバグ修正に役立つため
|
||||
|
||||
## 検証中の変更点
|
||||
|
||||
うまく動いていそうだったら本家に push されます
|
||||
|
||||
- 特定のユーザーのリプライをタイムラインから非表示する機能(「ブーストをミュート」のリプライ版)を追加
|
||||
- Docker/Podman の環境で `custom` ディレクトリの内容が反映されない不具合を修正
|
||||
- 画面を下に引いてタイムラインなどを更新する機能を追加(Misskey から取り込み)
|
||||
- 本家にもマージリクエストを出しました ([!10644](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10644))
|
||||
|
||||
## このフォークから本家 Firefish に輸出された変更点
|
||||
|
||||
このフォークは本家に push する前のテスト環境としても使われるため、有用な機能はよく輸出されます(そしてニッチな機能だけが残る)
|
||||
|
||||
- iOS で効果音と音楽の再生が干渉する問題を修正(Misskey から取り込み)
|
||||
- サーバーの管理者が左下のヘルプメニューに利用規約以外のページも固定できるように
|
||||
- 依存ライブラリのバージョンをアップデート
|
||||
- AiScript のバージョンも上がりました!
|
||||
- 絵文字ピッカーに表示されるカスタム絵文字の検索結果の件数を最大 100 件に変更(Misskey の変更を取り込み)
|
||||
- 投稿中に表示されるインスタンスティッカーをクリックするとサーバー情報を開くように
|
||||
- UI 用の言語とは別に、投稿翻訳に使用する言語を設定可能に
|
||||
- UI 用の言語は翻訳先の言語の第二候補として使われます(投稿の言語と投稿翻訳先に設定した言語が同じだった場合には UI 用の言語に翻訳されます)
|
||||
- 投稿言語を自動検出して外国語の投稿に翻訳ボタンを表示する設定を追加
|
||||
- 繁体中文への投稿翻訳を繁体字で表示する
|
||||
- DeepL 翻訳や LibreTranslate は簡体中文への翻訳しか提供していない……。
|
||||
- 「Firefish について」のページに Misskey の主要な貢献者を表示
|
||||
- このソフトウェアは Misskey のフォークであるため
|
||||
- 閲覧注意の投稿への返信で注釈の先頭に "re:" をつける設定を追加
|
||||
- 返信で閲覧注意は維持したいけどそのままの注釈を用いるのには違和感を覚えることがよくあるため
|
||||
- 猫耳の角を少し丸くする(Misskey から取り込み)
|
||||
- そのほうがかわいいため
|
||||
- インスタンスティッカーのツールチップに出るソフトウェア名で FoundKey, PeerTube, GNU social, WriteFreely などを正しく表示する
|
||||
|
||||
# 使用方法
|
||||
|
||||
## インストール
|
||||
|
||||
以下の方法でインストールできます。
|
||||
|
||||
- systemd 版(手動インストールのみ)
|
||||
- [Debian package](https://code.naskya.net/repos/Wmaym) 版
|
||||
- [Docker](https://hub.docker.com/r/naskya/firefish) 版
|
||||
|
||||
更新が最も早く反映されるのは systemd 版の手動インストールです。Docker イメージや Debian/Ubuntu 向けの deb ファイルの更新も定期的に行うようにしますが、Vervis にはそのようなことを自動で行う仕組みが無いのでちょっとつらいです。
|
||||
|
||||
### 自動でインストールする
|
||||
|
||||
[Ubuntu 向けのインストールスクリプト](https://code.naskya.net/repos/Wm6vm) があります。
|
||||
|
||||
### 手動でインストールする
|
||||
|
||||
基本的に本家版のインストールと同じ手順で行えますが、[PGroonga](https://pgroonga.github.io/ja/) のインストールが必要である点が異なります。
|
||||
|
||||
#### Docker 版
|
||||
|
||||
このリポジトリをクローンして `docker-compose.example.yml` を `docker-compose.yml` にコピーし、本家版と同様にサーバーを構築すればよいですが、そのまま起動するとデータベースのマイグレーションに失敗します。最初にデータベースのコンテナのみを起動させて以下のコマンドで PGroonga を有効にしてください(`firefish` と `firefish_db` はそれぞれ `.config/docker.env` や `.config/default.yml` に書いた PostgreSQL のユーザー名とデータベース名にしてください)。
|
||||
|
||||
```bash
|
||||
# DNS・ファイヤーウォール・リバースプロキシなどを各自で設定する
|
||||
|
||||
git clone https://code.naskya.net/naskya/firefish
|
||||
cd firefish
|
||||
cp docker-compose.example.yml docker-compose.yml
|
||||
cp .config/example.yml .config/default.yml
|
||||
|
||||
# docker-compose.yml, .config/default.yml, .config/docker.env を編集する
|
||||
|
||||
docker-compose up db --detach
|
||||
docker-compose exec db psql --command='CREATE EXTENSION pgroonga;' --user=firefish --dbname=firefish_db
|
||||
|
||||
./update.sh --install
|
||||
```
|
||||
|
||||
#### systemd 版
|
||||
|
||||
このリポジトリをクローンして、本家版と同様にサーバーを構築します。ビルド等の作業 (`pnpm install`, `pnpm run build`, `pnpm run migrate`) は添付のアップデートスクリプトによって一括で行えます。
|
||||
|
||||
```bash
|
||||
# DNS・ファイヤーウォール・リバースプロキシ・PostgreSQL・Redis などを各自でインストールして設定する
|
||||
|
||||
git clone https://code.naskya.net/naskya/firefish
|
||||
cd firefish
|
||||
cp .config/example.yml .config/default.yml
|
||||
|
||||
# .config/default.yml を編集する
|
||||
|
||||
sudo -u postgres psql --command "CREATE EXTENSION pgroonga;" --dbname firefish_db
|
||||
|
||||
./update.sh --install
|
||||
```
|
||||
|
||||
[インストール方法に関する私の記事](https://blog.naskya.net/post/6kic0tebueju/)も参考になるかもしれません。
|
||||
|
||||
## アップデート
|
||||
|
||||
### Docker 版(手動インストール・自動インストール)
|
||||
|
||||
重要なお知らせがある場合にはアップデートスクリプトを通じてお伝えするので、必ず `update.sh` を用いてアップデートしてください。
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. `update.sh` を実行し、表示される指示に従う
|
||||
|
||||
```bash
|
||||
./update.sh
|
||||
```
|
||||
|
||||
3. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
docker-compose up --detach
|
||||
```
|
||||
|
||||
### systemd 版(手動インストール)
|
||||
|
||||
重要なお知らせがある場合にはアップデートスクリプトを通じてお伝えするので、必ず `update.sh` を用いてアップデートしてください。
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. サーバーを停止する
|
||||
|
||||
```bash
|
||||
sudo systemctl stop yourserver.example.com
|
||||
```
|
||||
|
||||
3. `update.sh` を実行し、表示される指示に従う
|
||||
|
||||
```bash
|
||||
./update.sh
|
||||
```
|
||||
|
||||
4. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
sudo systemctl start yourserver.example.com
|
||||
```
|
||||
|
||||
### Debian package 版(自動インストール)
|
||||
|
||||
`apt` を利用してアップデートします。
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. パッケージをアップデートして動作を確認する
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
```
|
||||
|
||||
#### 正常にアップデートできなかった場合
|
||||
|
||||
私が対処する必要がある問題が発生している可能性もあるため、一人で解決しようとせずに `./update.sh` の[実行ログを私まで送ってください](https://code.naskya.net/naskya/firefish#私にコマンドの実行ログを送る)。
|
||||
|
||||
## [本家 Firefish](https://git.joinfirefish.org/firefish/firefish) からの乗り換え
|
||||
|
||||
### systemd 版
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. サーバーを停止する
|
||||
|
||||
```bash
|
||||
sudo systemctl stop yourserver.example.com
|
||||
```
|
||||
|
||||
3. Firefish がインストールされているディレクトリ (e.g., `/home/calckey/calckey`) の親ディレクトリ (e.g., `/home/calckey`) に移動する
|
||||
|
||||
```bash
|
||||
cd /home/calckey
|
||||
```
|
||||
|
||||
4. Firefish がインストールされているディレクトリ (e.g., `./calckey`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv calckey calckey.old
|
||||
```
|
||||
|
||||
5. 元々 Firefish がインストールされていたディレクトリ (e.g., `./calckey`) と同じ名前でこのリポジトリをクローンする
|
||||
|
||||
```bash
|
||||
git clone https://code.naskya.net/naskya/firefish calckey
|
||||
```
|
||||
|
||||
6. 必要なファイルを元のディレクトリからコピーする
|
||||
|
||||
```bash
|
||||
rm -rf calckey/files calckey/custom calckey/.config
|
||||
cp -r calckey.old/files calckey
|
||||
cp -r calckey.old/custom calckey
|
||||
cp -r calckey.old/.config calckey
|
||||
```
|
||||
|
||||
7. 全文検索エンジン(Meilisearch, Sonic, Elasticsearch のいずれか)を使用している場合には、`.config/default.yml` からその設定を削除またはコメントアウトする
|
||||
|
||||
先頭に `#` をつけると設定をコメントアウトできます。
|
||||
|
||||
```yaml
|
||||
#sonic:
|
||||
# host: localhost
|
||||
# port: 1491
|
||||
# auth: SecretPassword
|
||||
# collection: notes
|
||||
# bucket: default
|
||||
```
|
||||
|
||||
全文検索エンジンは停止またはアンインストールしてしまってよいです。本家の Firefish に戻るつもりがあるなら停止を、そうでなければアンインストールをおすすめします。
|
||||
|
||||
停止コマンドの例
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now sonic
|
||||
```
|
||||
|
||||
8. PostgreSQL のバージョンを確認する
|
||||
|
||||
```bash
|
||||
psql --version
|
||||
```
|
||||
|
||||
9. PGroonga をインストールする
|
||||
|
||||
コマンドの例(詳しくは[この投稿](https://post.naskya.net/notes/9ldi29amfanomef5)を参考にしてください)
|
||||
|
||||
```bash
|
||||
sudo apt install -y software-properties-common
|
||||
sudo add-apt-repository -y universe
|
||||
sudo add-apt-repository -y ppa:groonga/ppa
|
||||
sudo apt install -y wget lsb-release
|
||||
wget https://packages.groonga.org/ubuntu/groonga-apt-source-latest-$(lsb_release --codename --short).deb
|
||||
sudo apt install -y -V ./groonga-apt-source-latest-$(lsb_release --codename --short).deb
|
||||
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release --codename --short)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo apt update
|
||||
sudo apt install -y -V postgresql-14-pgdg-pgroonga
|
||||
```
|
||||
|
||||
10. `.config/default.yml` に書かれているデータベースの名前を確認する(以下の例では `mk1`)
|
||||
|
||||
```yaml
|
||||
db:
|
||||
host: localhost
|
||||
port: 5432
|
||||
db: mk1 # <---
|
||||
```
|
||||
|
||||
11. 以下のコマンドを実行して PGroonga の拡張機能を有効にする(`mk1` の部分は自分のデータベース名に変えて実行)
|
||||
|
||||
```bash
|
||||
sudo -iu postgres psql --command="CREATE EXTENSION pgroonga;" --dbname=mk1
|
||||
```
|
||||
|
||||
12. 新しい Firefish のディレクトリに入ってビルドする
|
||||
|
||||
```bash
|
||||
cd calckey
|
||||
./update.sh --install
|
||||
```
|
||||
|
||||
13. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
sudo systemctl start yourserver.example.com
|
||||
```
|
||||
|
||||
14. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf calckey.old
|
||||
```
|
||||
|
||||
### Docker 版
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. サーバーを停止する
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
3. Firefish がインストールされているディレクトリ (e.g., `/home/calckey/calckey`) の親ディレクトリ (e.g., `/home/calckey`) に移動する
|
||||
|
||||
```bash
|
||||
cd /home/calckey
|
||||
```
|
||||
|
||||
4. Firefish がインストールされているディレクトリ (e.g., `./calckey`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv calckey calckey.old
|
||||
```
|
||||
|
||||
5. 元々 Firefish がインストールされていたディレクトリ (e.g., `./calckey`) と同じ名前でこのリポジトリをクローンする
|
||||
|
||||
```bash
|
||||
git clone https://code.naskya.net/naskya/firefish calckey
|
||||
```
|
||||
|
||||
6. 必要なファイルを元のディレクトリからコピーする
|
||||
|
||||
```bash
|
||||
rm -rf calckey/files calckey/custom calckey/.config
|
||||
cp -r calckey.old/files calckey
|
||||
cp -r calckey.old/custom calckey
|
||||
cp -r calckey.old/.config calckey
|
||||
```
|
||||
|
||||
7. 以下のコマンドを実行して PGroonga を有効にする(firefish と firefish_db はそれぞれ `.config/docker.env` や `.config/default.yml` に書いた PostgreSQL のユーザー名とデータベース名にしてください)
|
||||
|
||||
```bash
|
||||
docker-compose up db --detach
|
||||
docker-compose exec db psql --command='CREATE EXTENSION pgroonga;' --user=firefish --dbname=firefish_db
|
||||
```
|
||||
|
||||
8. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
docker-compose up --detach
|
||||
```
|
||||
|
||||
9. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf calckey.old
|
||||
```
|
||||
|
||||
## このフォークから[本家 Firefish](https://git.joinfirefish.org/firefish/firefish) へ戻る
|
||||
|
||||
### systemd 版
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. サーバーを停止する
|
||||
|
||||
```bash
|
||||
sudo systemctl stop yourserver.example.com
|
||||
```
|
||||
|
||||
3. Firefish がインストールされているディレクトリ (e.g., `/home/calckey/calckey`) へ移動する
|
||||
|
||||
```bash
|
||||
cd /home/calckey/calckey
|
||||
```
|
||||
4. 最新版にアップデートする
|
||||
|
||||
```bash
|
||||
./update.sh
|
||||
```
|
||||
|
||||
5. `.config/default.yml` に書かれているデータベースの名前を確認する(以下の例では `mk1`)
|
||||
|
||||
```yaml
|
||||
db:
|
||||
host: localhost
|
||||
port: 5432
|
||||
db: mk1 # <---
|
||||
```
|
||||
|
||||
6. 次のコマンドでデータベースをいじる前に、そのコマンドが正常に動作するか確認する(`mk1` の部分は自分のデータベース名に変更する)
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -iu postgres psql --set='ON_ERROR_STOP=1' --dbname=mk1
|
||||
```
|
||||
|
||||
最後の行が `ROLLBACK` で終わっていれば問題ありません。そうでない場合には以下の[コマンドの実行結果を私に送ってください](https://code.naskya.net/naskya/firefish#私にコマンドの実行ログを送る)。
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -iu postgres psql --echo-all --set='ON_ERROR_STOP=1' --dbname=mk1
|
||||
```
|
||||
|
||||
7. このフォークで加えられたデータベースへの変更を実際に取り消す(`mk1` の部分は自分のデータベース名に変更する)
|
||||
|
||||
```bash
|
||||
sudo -iu postgres psql --file=neko/revert.sql --dbname=mk1
|
||||
```
|
||||
|
||||
8. PGroonga をアンインストールする
|
||||
|
||||
コマンドの例
|
||||
|
||||
```bash
|
||||
sudo apt purge --remove postgresql-14-pgdg-pgroonga
|
||||
sudo add-apt-repository --remove ppa:groonga/ppa
|
||||
sudo apt-key del ACCC4CF8
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
9. Firefish がインストールされているディレクトリの親ディレクトリ (e.g., `/home/calckey`) に行く
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
```
|
||||
|
||||
10. Firefish がインストールされているディレクトリ (e.g., `./calckey`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv calckey calckey.old
|
||||
```
|
||||
|
||||
11. Firefish がインストールされているディレクトリと同じ名前で本家版の Firefish を clone する
|
||||
|
||||
```bash
|
||||
git clone https://git.joinfirefish.org/firefish/firefish.git calckey
|
||||
```
|
||||
|
||||
12. 必要なファイルをコピーする
|
||||
|
||||
```bash
|
||||
rm -rf calckey/files calckey/custom calckey/.config
|
||||
cp -r calckey.old/files calckey
|
||||
cp -r calckey.old/custom calckey
|
||||
cp -r calckey.old/.config calckey
|
||||
```
|
||||
|
||||
13. 新しい Firefish のディレクトリ (e.g., `./calckey`) に入り、`develop` ブランチに行く(実際には既に `develop` にいるはず)
|
||||
|
||||
```bash
|
||||
cd calckey
|
||||
git checkout develop
|
||||
```
|
||||
|
||||
14. Firefish をビルドする
|
||||
|
||||
```bash
|
||||
corepack prepare pnpm@latest --activate
|
||||
pnpm i
|
||||
NODE_ENV=production pnpm run build
|
||||
pnpm run migrate
|
||||
```
|
||||
|
||||
15. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
sudo systemctl start yourserver.example.com
|
||||
```
|
||||
|
||||
16. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf calckey.old
|
||||
```
|
||||
|
||||
#### 注意
|
||||
|
||||
この手順を踏むとあなたの Firefish サーバーは `develop` 版になります。他のバージョンを動かしたい場合も、**次のアップデートがリリースされるまでは `develop` 版を動かしてください**。
|
||||
|
||||
例えば `beta` 版を動かしたい場合、次に `beta` 版がリリースされたらそちらに移れます。
|
||||
|
||||
```bash
|
||||
git checkout beta
|
||||
git pull --ff
|
||||
corepack prepare pnpm@latest --activate
|
||||
pnpm i
|
||||
NODE_ENV=production pnpm run build
|
||||
pnpm run migrate
|
||||
```
|
||||
|
||||
# 補足
|
||||
|
||||
## 私にコマンドの実行ログを送る
|
||||
|
||||
実行したいコマンドの後ろに `|& tee /tmp/fflog` をつけてコマンドを実行します。例えば実行したいコマンドが `./update.sh` ならば
|
||||
|
||||
```bash
|
||||
./update.sh |& tee /tmp/fflog
|
||||
```
|
||||
|
||||
とし、実行したいコマンドが
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -iu postgres psql --echo-all --set='ON_ERROR_STOP=1' --dbname=mk1
|
||||
```
|
||||
|
||||
ならば
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -iu postgres psql --echo-all --set='ON_ERROR_STOP=1' --dbname=mk1 |& tee /tmp/fflog
|
||||
```
|
||||
|
||||
とします。
|
||||
|
||||
するとコマンドの実行ログが `/tmp/fflog` に保存されるので、保存されたテキスト全体をサーバーの OS などの環境の情報とともに[私](https://post.naskya.net/@dev)に送ってください。
|
||||
|
||||
ログのうちの参考になりそうだと思った一部だけを抜粋して送ることは絶対にしないでください。必要な情報が欠落していてもう一度全体を送り直してもらうことになったり、私が対処方法の判断を誤ったりする可能性が高まったりします。
|
||||
|
||||
テキストが一つの投稿に収まる長さの場合はコードブロックの記法(``` で囲む)を用いて投稿してもらってよいです。ログが一投稿に収まらない長さの場合は [Pastebin](https://pastebin.com/) などのサービスを使って共有してください。投稿にログファイルを直接添付して送ることはしないでください。
|
||||
|
||||
ログを私に送ったら `/tmp/fflog` は削除してよいです。
|
||||
|
||||
```bash
|
||||
rm /tmp/fflog
|
||||
```
|
||||
- [本家版と異なる点](https://code.naskya.net/naskya/firefish/source-by/main/docs/changes.md)
|
||||
- [インストール方法](https://code.naskya.net/naskya/firefish/source-by/main/docs/install.md)
|
||||
- [アップデート方法](https://code.naskya.net/naskya/firefish/source-by/main/docs/update.md)
|
||||
- [本家版からの移行方法](https://code.naskya.net/naskya/firefish/source-by/main/docs/migrate.md)
|
||||
- [本家版への移行方法](https://code.naskya.net/naskya/firefish/source-by/main/docs/migrate_back.md)
|
||||
- [開発への協力方法](https://code.naskya.net/naskya/firefish/source-by/main/docs/contributing.md)
|
||||
|
|
17
dev/Makefile
Normal file
17
dev/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
|||
.PHONY: recreate
|
||||
recreate: down up
|
||||
|
||||
|
||||
.PHONY: down
|
||||
down:
|
||||
podman-compose down
|
||||
|
||||
|
||||
.PHONY: up
|
||||
up:
|
||||
podman-compose up --detach
|
||||
sleep 2
|
||||
podman-compose exec db psql \
|
||||
--user=firefish \
|
||||
--dbname=firefish_db \
|
||||
--command='CREATE EXTENSION pgroonga;'
|
16
dev/docker-compose.yml
Normal file
16
dev/docker-compose.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
version: "3"
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: docker.io/redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
db:
|
||||
image: docker.io/groonga/pgroonga:latest-alpine-16
|
||||
environment:
|
||||
- "POSTGRES_PASSWORD=password"
|
||||
- "POSTGRES_USER=firefish"
|
||||
- "POSTGRES_DB=firefish_db"
|
||||
ports:
|
||||
- "5432:5432"
|
202
docs/changes.md
Normal file
202
docs/changes.md
Normal file
|
@ -0,0 +1,202 @@
|
|||
# 本家版からの変更点
|
||||
|
||||
## Firefish そのものに関する変更点(メタな変更点)
|
||||
|
||||
- [ローリングリリース](https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9)を採用
|
||||
- いわゆる「新バージョンのリリース」はありません。細かい更新が頻繁に行われるので、好きなタイミングでアップデートしてください。
|
||||
- バージョン番号は `{本家のバージョン}+neko:{コミットの日付}.{コミットハッシュの上 2 桁}` です。
|
||||
- 例えば [`6424b685e9` というコミット](https://code.naskya.net/repos/a3WPw/commits/6424b685e971578427c8db5b14710494c5cdc0fd)の直後のバージョンは `1.0.5-dev20+neko:231107.64` です。
|
||||
- 元々私は `neko.なんとか` というドメインで登録を一般開放したサーバーを立てようと思っていて、そのサーバーにこの Firefish をインストールしようと思っていたことからバージョン番号に `neko` が含まれています。
|
||||
- 現在は生活に余裕が無く、管理に時間を割けなそうにないためこのサーバーを立てる計画は中断しています。
|
||||
- この Firefish はよく Firefish neko flavor と呼ばれていますが、これはこのバージョン番号に由来します。私自身は特にこの呼称を普及させたいわけではなかったのですが、[私のアカウント](https://post.naskya.net/@dev)の数割のフォロワーが英語圏の本家 Firefish の利用者であるため単に「この機能を追加しました!」などと投稿すると本家版の更新と誤解される恐れがありますし、「私の Firefish フォークにこの機能を追加しました!」などと投稿すると私が本家 Firefish の開発を離れて新たなハードフォークを作っているのだと誤解される恐れがあるため、投稿を機械翻訳で英訳されて読まれてもなるべく誤解されないための苦肉の策としてこの呼称を使い始めました。このソフトフォークはあくまで本家 Firefish の私による「味付け」です。
|
||||
- 依存ライブラリをほとんど常に最新版にアップデート
|
||||
- 本家版を更新する前にちゃんと動くか実験したいという意図もあります
|
||||
|
||||
## クライアントの変更点
|
||||
|
||||
### 主要な変更点
|
||||
|
||||
- 投稿ごとに言語を指定できるように([!10616](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10616) を独断でマージ)
|
||||
- これにより Mastodon の翻訳機能や言語フィルターなどが正常に機能します。今後 Firefish 側でもこの情報をもっと活用できるようにしたいです。
|
||||
- 検索フィルターを強化
|
||||
- 以下の機能があります
|
||||
- AND 検索
|
||||
- OR 検索
|
||||
- 自分の(未収載・フォロワー限定・ダイレクト・秘密を含む)全ての投稿からの検索
|
||||
- 特定のユーザーの投稿の検索
|
||||
- 特定のサーバーの投稿の検索
|
||||
- 特定の期間の投稿の検索
|
||||
- 添付ファイル付きの投稿の検索
|
||||
- 「秘密」という公開範囲を追加
|
||||
- 宛先無しのダイレクト投稿を言い換えているだけです
|
||||
- 既存の投稿を削除せずに後から秘密にすることもできます
|
||||
- モバイル表示の下部のチャットボタンをアカウント切り替えボタンに変更可能に
|
||||
- これ無しで PWA で複数アカウントを使おうとすると腱鞘炎になる
|
||||
- ローカルタイムラインの位置をグローバルタイムラインの直前に移動
|
||||
- ローカルタイムラインよりもソーシャルタイムラインのほうが使いやすいと考えたため
|
||||
- TODO: もっとカスタムできるようにして、本家にもその機能を入れたい ([#rw0Dw](https://code.naskya.net/decks/4wJQ3/tickets/rw0Dw))
|
||||
- 画面を下に引いてタイムラインなどを更新する機能を追加([Misskey から取り込み](https://github.com/misskey-dev/misskey/commit/c239058624dcd880ec1c5f3c436f3a2a06fc22c3))
|
||||
- 本家にもマージリクエストを出しています ([!10644](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10644))
|
||||
|
||||
### 細かい変更点
|
||||
|
||||
- モバイル表示の下部のウィジェットボタンを再読み込みボタンに変更可能に
|
||||
- スマートフォンでウィジェットは使わないけど再読み込みはたくさんする人はいそう
|
||||
- 設定のバックアップファイルに `misskeyVersion` の値が含まれていなくても警告しないように変更
|
||||
- TODO: 本家版にもマージリクエストを出す
|
||||
- RTL Layout(右から左に書く言語の表示)の部分的なサポート([!10452](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10452) を独断でマージ)
|
||||
- アップデート時に更新内容を確認できる機能を追加
|
||||
- HTML のコードに入るコメントアートを削除
|
||||
- 全ページにこんなの入れなくても……
|
||||
- デフォルトではバイブレーションを無効に
|
||||
- 投稿と投稿の間を空けて表示する設定をデフォルトでは無効に
|
||||
- Enter キーのみでチャットを送信する設定をデフォルトでは無効に
|
||||
- デフォルトのアイコンの太さを細めに変更
|
||||
- スタイルを選択する画面のサンプルのアイコンを星に変更
|
||||
- 標準のフォントを Atkinson Hyperlegible にする変更を取り消し
|
||||
- フォントを変更したい場合は[このカスタム CSS](https://gitlab.com/LunarEclipse363/lunar-misskey-tweaks#setting-a-different-font) を使ってください
|
||||
- 簡体中文の翻訳が存在しない項目では繁体中文の翻訳を用いるように(本家では逆)
|
||||
- [サポミク](https://fedi.sup39.dev/@sup39)さんが独自機能に使われているラベルの繁体中文訳を提供してくださったため
|
||||
- オンラインステータスが非公開のアカウントにはステータスを表す丸印を表示しないように
|
||||
- 灰色の丸が表示されていてもそんなに嬉しくないため
|
||||
- デフォルトで検索エンジンからのクロールを拒否するように変更
|
||||
- 検索の MFM で使用する検索エンジンを設定から変更可能に
|
||||
- 以下の選択肢から選べます
|
||||
- DuckDuckGo (duckduckgo.com)
|
||||
- SearXNG (searx.be)
|
||||
- Google Search (google.com)
|
||||
- Moon Search (search.naskya.net)
|
||||
- まだこの検索エンジンは作っていません……
|
||||
- サーバーの投稿検索
|
||||
- 身バレ防止の設定を追加
|
||||
- 「おかえりなさい、◯◯さん」が出ないようにできるように
|
||||
- 自分のアイコンを非表示にできるように
|
||||
- 自分の名前と ID を非表示にできるように
|
||||
- 名前と ID の部分をただ空白にするだけです
|
||||
- ユーザーページのデフォルトのタブを「投稿と返信」に変更
|
||||
- タイムラインにリプライを表示する設定をデフォルトで有効に
|
||||
- 未読通知のタブをリアクションの通知を表示するタブに変更
|
||||
- 未読のタブ、使ってる人いる?
|
||||
- MFM チートシートのボタンを投稿画面から左下のヘルプメニューに移動
|
||||
- これがあるために投稿画面下部のボタンが 2 段になってしまうことがあるため
|
||||
- 「フォローされています」の表示を目立たせられるように
|
||||
- デフォルトの表示は目立たないため
|
||||
- 投稿ボタンを巨大にできるように
|
||||
- [mstdn.maud.io / mstdn.poyo.me の機能](https://mstdn.poyo.me/@prime/110668364208741253) を真似しました
|
||||
- 猫のアカウントはアイコンを常に丸く表示する
|
||||
- そのほうがかわいいため
|
||||
- NSFW メディアを隠す設定をブラウザごとの設定からブラウザごとかつアカウントごとの設定に変更
|
||||
- 「このアカウントでは NSFW の画像を常に表示したい」みたいな需要が私にあったため
|
||||
- インスタンスティッカーをデフォルトで常に表示する
|
||||
- そのほうが楽しいと思ったから
|
||||
- 藍ちゃんウィジェットの復活
|
||||
- インスタンスティッカーのツールチップにソフトウェアのバージョン番号も表示する
|
||||
- 気になるから
|
||||
- いいねボタン(リアクションピッカーの左にある、⭐とか👍のリアクションをワンクリックで押せるやつ)で空のリアクション(Mastodon がふぁぼで送ってくるものと同じ)ではなく本当にその絵文字リアクション(⭐とか👍とか)を送るようにする
|
||||
- 最新の Misskey ではデフォルトリアクションが❤️になったため空のリアクションを送ると❤️として表示されてしまうが、❤️は ℒℴ𝓋ℯ... という気持ちを伝えるためのリアクションであってただの「いいね」とは異なるため、このボタンで❤️は送りたくないから
|
||||
- 通知の表示を簡潔にする
|
||||
- 「がリアクションしました」とかリプライの上にある白い線とかが邪魔に思えたため
|
||||
- 一部の表示の色も Misskey の通知の色が個人的に好みだったので戻しました
|
||||
- インスタンスティッカーに表示するサーバーのアイコンとして favicon を優先する
|
||||
- favicon のほうがよくカスタマイズされているため
|
||||
- TODO: サーバーによってはちゃんと動いていない気がするので調べる ([#13EQ3](https://code.naskya.net/decks/4wJQ3/tickets/13EQ3))
|
||||
- 誤爆しやすい位置にあるフォローボタンを隠す設定を追加
|
||||
- フォローを誤爆すると悲しいため
|
||||
- 投稿プレビューをデフォルトでオンにする設定を追加
|
||||
|
||||
## サーバーの変更点
|
||||
|
||||
### 主要な変更点
|
||||
|
||||
- 非ログインユーザーにもローカルタイムラインとグローバルタイムラインを公開できるように変更
|
||||
- コントロールパネルから設定すると `https://server.example.com/timeline` で公開されます
|
||||
- 全文検索のエンジンを [PGroonga](https://pgroonga.github.io/) に変更([tamaina さんの PGroonga パッチ](https://gist.github.com/tamaina/29e88e02d0dc5acfa2f50b3347d3d20d)を拡張)
|
||||
- Meilisearch, Elasticsearch, Sonic は使えません
|
||||
- モデレーターでない一般ユーザーにもカスタム絵文字の管理権を与えられるように変更
|
||||
- カスタム絵文字の管理が大変なサーバー管理者さんがたくさんいらっしゃったのでこの機能を追加するべきではないか他の開発者に訊いたところロール機能の実装を待つべきだと言われてしまったが、Firefish のロール機能は現状では仕様がまだ固まっておらず実装までに時間が掛かると考えられるため
|
||||
- 以下の権限を与えられます
|
||||
- 不許可: 絵文字の管理を許可しない
|
||||
- 追加: 新しい絵文字の追加のみを許可する
|
||||
- 追加と変更: 「追加」に加え、既存のカスタム絵文字の名前・カテゴリ・タグ・ライセンスの編集を許可する
|
||||
- 全て許可:「追加と変更」に加え、既存のカスタム絵文字の削除を許可する
|
||||
- 特定のユーザーのリプライをタイムラインから非表示する機能(「ブーストをミュート」のリプライ版)を追加
|
||||
- 本家版にもマージリクエストを出しています ([!10658](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10658))
|
||||
|
||||
### 細かい変更点
|
||||
|
||||
- 設定の初期値を変更
|
||||
- 新規登録を無効化
|
||||
- 新規登録を受け付けたくないのに無効化する前にアカウントを登録されてしまうことを防ぐため
|
||||
- プライベートモード(連合しないモード)を有効化
|
||||
- サーバーの準備が整っていないうちにリモートサーバーに認識されてしまうことを防ぐため
|
||||
- サーバーメトリクスの表示を有効化
|
||||
- 有効化しているサーバーが多いため
|
||||
- ランダムなアイコンの生成を無効化
|
||||
- ランダムなアイコンはそんなにかわいくないため
|
||||
- パフォーマンス向上のためアクティブユーザー以外のチャート生成を無効化
|
||||
- サードパーティー製クライアントが動かなくなるのを阻止するため API のエンドポイントは残していますが、叩いても `0` が並んだ配列しか返しません。
|
||||
- 猫語で "nA" を "nYA" に置換しない
|
||||
- この置き換えはあまり嬉しくないことが多い
|
||||
- `reset-db` という API を無効化
|
||||
- エンドポイント自体は残してありますが、叩いても何もしません
|
||||
- データベースをリセットする API って何?怖すぎる
|
||||
- ユーザーページでプロフィール画像を選択すると画像を拡大する([Catodon から取り込み](https://codeberg.org/catodon/catodon/commit/a4b74d9b6bd7db56f0a4ce3439c29b9df4b41100))
|
||||
- 本家版にもマージリクエストを出しています ([!10659](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10659))
|
||||
- 署名アルゴリズムとして ECDSA や Ed25519 なども受け入れる([mei23/misskey-v12 から取り込み](https://github.com/mei23/misskey-v12/commit/b008e1e7169ea7cbb4a49fb1856f8cd838333230))
|
||||
- TODO: 本家版にもマージリクエストを出す
|
||||
- Pleroma のチャットに対応([Catodon から取り込み](https://codeberg.org/catodon/catodon/commit/0ed49d05a98ecb3df938f5558fdfe7011844732f))
|
||||
- 本家版にもマージリクエストを出しています ([!10660](https://git.joinfirefish.org/firefish/firefish/-/merge_requests/10660))
|
||||
- 翻訳機能にて、投稿言語が指定されていない場合にのみ言語の自動検出を用いるように変更
|
||||
- TODO: 本家版にもマージリクエストを出す
|
||||
- 中国語の猫モードでは 0.1 の確率で投稿の末尾に「喵」を追加するように
|
||||
- TODO: 様子を見て、良さそうだったら本家版にもマージリクエストを出す
|
||||
- `emojis` API(Misskey v13- 互換)を追加([firefish-mkdir から取り込み](https://git.mkdir.uk/hiira/firefish-mkdir/commit/e98af2b2a78463bd64393936dbe223127552bff5))
|
||||
- ログインしていなければ投稿検索ができないように
|
||||
- 攻撃対策のため
|
||||
- もしこのせいでサードパーティークライアントに不具合が出る場合には変更するかもしれません
|
||||
- 管理者アカウントも引っ越しできるように
|
||||
- リアクションの履歴を公開する設定をデフォルトで有効に
|
||||
- 私がみんなのリアクションを見たいと思っているため
|
||||
- もちろん設定から無効にできます
|
||||
- 最大 15 件の投稿を固定できるように
|
||||
- 5 件は少ないと思ったため
|
||||
- アンテナにフォロー中のユーザーのホーム投稿も表示する
|
||||
- フォロー中のユーザーの投稿は見たいから
|
||||
- 支援者リストをファイルから読み込む
|
||||
- 外部のサーバーが落ちるとユーザーページが開けなくなることを防ぐため
|
||||
- 閲覧注意の注釈~~と添付ファイルの代替テキスト~~もアンテナで調べる対象にする
|
||||
- ~~「そぎぎ」でアンテナを作れる~~
|
||||
- TODO: 代替テキストがちゃんと調べられていない気がするので直す ([#q32v3](https://code.naskya.net/decks/4wJQ3/tickets/q32v3))
|
||||
- インデックス拒否に `noindex` に加えて `nofollow,noarchive,nocache,noimageindex` も指定
|
||||
- デフォルトの robots.txt の設定を変更し、クローラーを拒否するように
|
||||
- joinfirefish と FediDB のクローラーは許可しています
|
||||
|
||||
## コンテナイメージの変更点
|
||||
|
||||
- ベースイメージに [`docker.io/node:21-slim`](https://hub.docker.com/layers/library/node/21-slim/images/sha256-5a3290b496bb63e1e19d440810a55eea3e004eeda7cc15f75a8b256995e41542) を使用
|
||||
- イメージのビルドに [buildah](https://github.com/containers/buildah) を使用
|
||||
- もし Docker との互換性に問題があったりしたら教えてください
|
||||
- Rust のリンカーに [mold](https://github.com/rui314/mold) を使用
|
||||
- `custom` ディレクトリの内容が反映されない不具合を修正
|
||||
- TODO: 本家版も修正する
|
||||
|
||||
## このフォークから本家 Firefish に輸出された変更点
|
||||
|
||||
このフォークは本家に push する前のテスト環境としても使われるため、有用な機能はよく輸出されます(そしてニッチな機能だけが残る)
|
||||
|
||||
- iOS で効果音と音楽の再生が干渉する問題を修正([Misskey から取り込み](https://github.com/misskey-dev/misskey/commit/38d6580a36bb6474153536edb50b59376ce16779))
|
||||
- サーバーの管理者が左下のヘルプメニューに利用規約以外のページも固定できるように
|
||||
- 絵文字ピッカーに表示されるカスタム絵文字の検索結果の件数を最大 100 件に変更([Misskey から取り込み](https://github.com/misskey-dev/misskey/commit/e11320dbb70bbae0da78975718cc06b440daa6a4))
|
||||
- 投稿中に表示されるインスタンスティッカーをクリックするとサーバー情報を開くように
|
||||
- UI 用の言語とは別に、投稿翻訳に使用する言語を設定可能に
|
||||
- UI 用の言語は翻訳先の言語の第二候補として使われます(投稿の言語と投稿翻訳先に設定した言語が同じだった場合には UI 用の言語に翻訳されます)
|
||||
- 投稿言語を自動検出して外国語の投稿に翻訳ボタンを表示する設定を追加
|
||||
- 繁体中文への投稿翻訳を繁体字で表示する
|
||||
- DeepL 翻訳や LibreTranslate は簡体中文への翻訳しか提供していない……。
|
||||
- 「Firefish について」のページに Misskey の主要な貢献者を表示
|
||||
- このソフトウェアは Misskey のフォークであるため
|
||||
- 閲覧注意の投稿への返信で注釈の先頭に "re:" をつける設定を追加
|
||||
- 返信で閲覧注意は維持したいけどそのままの注釈を用いるのには違和感を覚えることがよくあるため
|
||||
- 猫耳の角を少し丸くする([Misskey から取り込み](https://github.com/misskey-dev/misskey/commit/1a96425768b743cf6a7f93b7813c082152497461))
|
||||
- そのほうがかわいいため
|
||||
- インスタンスティッカーをマウスオーバーしたときに出るソフトウェア名で FoundKey, PeerTube, GNU social, WriteFreely などを正しく表示する
|
98
docs/contributing.md
Normal file
98
docs/contributing.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
# 開発への協力方法
|
||||
|
||||
これは個人的なフォークなので、基本的には本家 Firefish の開発に協力してもらえればと思います。ただし、最近は本家 Firefish へのマージリクエストのマージが滞りがちですし、本家版にいきなり貢献するのはハードルが高いと思ったりマージしてもらえるか分からないニッチな機能を作ったりした場合にはこのフォークへ貢献していただいてもよいです。
|
||||
|
||||
現状、マージリクエストを直接送る方法が無いので patch ファイルまたは別のサイトにフォークしたリポジトリに追加したコミットへの URL を[私](https://post.naskya.net/@dev)に送ってください。
|
||||
|
||||
## 開発の方法
|
||||
|
||||
### 環境構築
|
||||
|
||||
1. 以下のソフトウェアをインストールする
|
||||
|
||||
- podman
|
||||
- podman-compose
|
||||
- make
|
||||
- nodejs
|
||||
- pnpm
|
||||
- shellcheck
|
||||
- sea-orm-cli
|
||||
- cargo
|
||||
|
||||
2. コンテナを起動し、PGroonga を有効化する
|
||||
|
||||
```bash
|
||||
cd dev
|
||||
make up
|
||||
```
|
||||
|
||||
3. 以下の内容の `.config/default.yml` を作成する
|
||||
|
||||
```yaml
|
||||
url: http://localhost:3000
|
||||
port: 3000
|
||||
db:
|
||||
host: localhost
|
||||
port: 5432
|
||||
db: firefish_db
|
||||
user: firefish
|
||||
pass: password
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
```
|
||||
|
||||
コンテナを作り直すと簡単にデータベースを初期化できます。
|
||||
|
||||
```bash
|
||||
cd dev
|
||||
make
|
||||
```
|
||||
|
||||
参考にした記事: [Firefish 開発環境の準備(バックエンド向け)](https://hackmd.io/@nmkj-io/HJHNbM_8a)
|
||||
|
||||
### 実行
|
||||
|
||||
```bash
|
||||
make debug
|
||||
```
|
||||
|
||||
### コミット前に行う確認
|
||||
|
||||
```bash
|
||||
make pre-commit
|
||||
```
|
||||
|
||||
### コミットメッセージ
|
||||
|
||||
コミットメッセージの書き方に厳密な規則はありませんが、私は以下のようにコミットメッセージを書いているのである程度それに則ってもらえると助かります。でも適当で大丈夫です(更新を取り込む際にコミットメッセージが書き換えられる場合もありますが、ご了承ください)。
|
||||
|
||||
コミットメッセージは英語で書き、場合によっては冠詞などを適度に省いて短く収めてください。長い説明が必要な場合には、以下の規則で 1 行目にざっくりとしたコミットメッセージを書いてから 2 つ改行して(つまり 1 行空けて)詳細説明を続けてください。
|
||||
|
||||
コミットメッセージの頭文字は大文字にせず、動詞から始める場合には現在形を用いてください。例えば、`feat: Added xxxxx` とはせずに `feat: add xxxxx` としてください。
|
||||
|
||||
1. 重大な不具合の緊急修正: `hotfix: 不具合の内容`
|
||||
- プログラム自体が起動しなくなったり投稿が一切できなくなるなどの重大な不具合を回避するための更新には `hotfix:` を頭につけます。
|
||||
2. ドキュメントのみの更新: `docs: 更新の概要`
|
||||
- 内容がドキュメントの更新のみの場合、`docs:` を頭につけます。たとえ更新内容が誤字の訂正であったとしても `fix: typo` ではなく `docs: fix typo` とします。
|
||||
3. 翻訳の更新: `locale: 更新の概要`
|
||||
- `locales/` 以下のファイルをいじった場合のコミットなどがこれに該当します。
|
||||
4. コンテナイメージに関する更新: `container: 更新の概要`
|
||||
- `Dockerfile` や `docker-compose.yml` の更新など、Podman/Docker のユーザー以外には一切影響しない更新がこれに該当します。
|
||||
5. Firefish のプログラム本体には変更を加えない更新: `dev: 更新の概要`
|
||||
- アップデートスクリプトや Makefile の更新など、プログラム本体への変更は加えない場合には `dev:` を頭につけます。
|
||||
- `packages.json`, `packages/`, `locales/` に変更を全く加えていないコミットは大体これに該当します。
|
||||
- 開発とは全く関係無い場合には `meta:` を用いてもよいです。
|
||||
6. 不具合の修正: `fix: 不具合の内容`
|
||||
7. 機能の追加: `feat: 更新の概要`
|
||||
8. パフォーマンスの向上のための再設計: `perf: 再設計の概要`
|
||||
9. Web クライアントの見た目の変更: `style: 更新の概要`
|
||||
10. プログラムの再設計: `refactor: 再設計の概要`
|
||||
11. その他の雑務: `chore: 更新の概要`
|
||||
- コードのフォーマットや非常に小規模なプログラムの書き換え(一箇所の `||` を `??` に書き換えるなど)や依存パッケージの更新がこれに該当します。
|
||||
|
||||
更新が本当に小規模な場合には `:` の直前に `(minor)` を入れても良いです(例: `docs (minor): fix typo in README.md`)が、ほとんどの場合にこれは使う必要がありません。
|
||||
|
||||
## 注意事項
|
||||
|
||||
データベースのマイグレーションを伴う変更を加える場合にはマイグレーションのファイルを [`packages/backend/migration-neko`](https://code.naskya.net/naskya/firefish/source-by/main/packages/backend/migration-neko) の下に作成し、マイグレーションを打ち消す SQL クエリを [`neko/revert.sql`](https://code.naskya.net/naskya/firefish/source-by/main/neko/revert.sql) の**一番上に**追記してください。
|
224
docs/install.md
Normal file
224
docs/install.md
Normal file
|
@ -0,0 +1,224 @@
|
|||
# インストール方法
|
||||
|
||||
## サーバーに直接インストールする
|
||||
|
||||
1. サーバーに git, Nodejs, npm, PostgreSQL, PGroonga, Redis, Rust をインストールします。Arch Linux にインストールする場合には[私のブログ](https://blog.naskya.net/post/6kic0tebueju/)が参考になるかもしれません。
|
||||
|
||||
Ubuntu や Debian にインストールする場合には、例えば以下のようになります。
|
||||
|
||||
```bash
|
||||
# Rust のインストール
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
|
||||
# Nodejs v21 のインストールの準備
|
||||
NODE_MAJOR=21
|
||||
sudo apt install --no-install-recommends curl ca-certificates gnupg
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
|
||||
| sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] "https://deb.nodesource.com/node_${NODE_MAJOR}.x" nodistro main" \
|
||||
| sudo tee /etc/apt/sources.list.d/nodesource.list
|
||||
|
||||
# PostgreSQL のインストールの準備
|
||||
echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||
curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
|
||||
# PGroonga のインストールの準備
|
||||
sudo apt install --no-install-recommends software-properties-common wget
|
||||
sudo add-apt-repository -y universe
|
||||
sudo add-apt-repository -y ppa:groonga/ppa
|
||||
wget https://packages.groonga.org/ubuntu/groonga-apt-source-latest-$(lsb_release --codename --short).deb
|
||||
sudo apt install --no-install-recommends ./groonga-apt-source-latest-$(lsb_release --codename --short).deb
|
||||
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release --codename --short)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
|
||||
# Redis のインストールの準備
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
|
||||
# 各ソフトウェアのインストール
|
||||
sudo apt update
|
||||
sudo apt install --no-install-recommends git nodejs postgresql-16 postgresql-16-pgdg-pgroonga redis-server
|
||||
|
||||
# pnpm を有効化
|
||||
sudo corepack enable
|
||||
|
||||
# PostgreSQL, Redis を起動
|
||||
systemctl enable --now postgresql redis-server
|
||||
```
|
||||
|
||||
2. このリポジトリを複製し、リポジトリのディレクトリに移る
|
||||
|
||||
```bash
|
||||
git clone --branch=main https://code.naskya.net/naskya/firefish
|
||||
cd firefish
|
||||
```
|
||||
|
||||
3. 設定ファイルのテンプレートを複製する
|
||||
|
||||
```bash
|
||||
cp .config/example.yml .config/default.yml
|
||||
```
|
||||
|
||||
4. PostgreSQL のユーザー名・データベース名・パスワードを決める(決めるだけでこの工程にコマンドの操作は無い)
|
||||
|
||||
5. `./config/default.yml` を編集する
|
||||
|
||||
```bash
|
||||
vim .config/default.yml
|
||||
```
|
||||
|
||||
`url` という項目を `example.com` から使いたいドメイン名に変更する
|
||||
|
||||
```yaml
|
||||
# Final accessible URL seen by a user.
|
||||
url: https://example.com/
|
||||
```
|
||||
|
||||
データベースの設定を変える(データベース名・ユーザー名・パスワードはそれぞれさっき自分で決めたもの)
|
||||
|
||||
```yaml
|
||||
db:
|
||||
host: localhost # 変えない
|
||||
port: 5432 # 変えない
|
||||
|
||||
db: firefish_db # ここをデータベース名に変える
|
||||
|
||||
user: firefish # ここをデータベースのユーザー名に変える
|
||||
pass: very_strong_password # ここをデータベースのパスワードに変える
|
||||
```
|
||||
|
||||
6. PostgreSQL のユーザーとデータベースを作る
|
||||
|
||||
```bash
|
||||
POSTGRES_DB='データベース名'
|
||||
POSTGRES_USER='ユーザー名'
|
||||
POSTGRES_PASSWORD='パスワード'
|
||||
|
||||
sudo -u postgres psql --command="CREATE ROLE ${POSTGRES_USER} LOGIN PASSWORD '${POSTGRES_PASSWORD}';"
|
||||
sudo -u postgres psql --command="CREATE DATABASE ${POSTGRES_DB} OWNER ${POSTGRES_USER} encoding = 'UTF8';"
|
||||
```
|
||||
|
||||
7. PGroonga を有効化する
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql --dbname="${POSTGRES_DB}" --command='CREATE EXTENSION pgroonga;'
|
||||
```
|
||||
|
||||
8. Firefish をビルドする
|
||||
|
||||
```bash
|
||||
./update.sh --install --native
|
||||
```
|
||||
|
||||
9. Firefish を起動するための systemd サービスを作る
|
||||
|
||||
`/etc/systemd/system/firefish.service` というテキストファイルを作り、Firefish をインストールしたディレクトリで `pnpm run start` を実行させるようにします。[私のブログ](https://blog.naskya.net/post/6kic0tebueju/#firefish-%E3%82%92%E8%B5%B7%E5%8B%95)や [systemd サービスに関する記事](https://wiki.archlinux.jp/index.php/Systemd#.E3.83.A6.E3.83.8B.E3.83.83.E3.83.88.E3.83.95.E3.82.A1.E3.82.A4.E3.83.AB)などを参考にしてください。
|
||||
|
||||
以下の設定を行えば大丈夫なはずです。
|
||||
- 実行するユーザーをグループを指定する
|
||||
- `which pnpm` で `pnpm` コマンドの場所(例えば `/usr/bin/pnpm`)を探し、`ExecStart` で `pnpm run start` を実行させる
|
||||
- 例えば `ExecStart=/usr/bin/pnpm run start`
|
||||
- リポジトリのディレクトリを `WorkingDirectory` に設定する
|
||||
- `Environment="NODE_ENV=production"`
|
||||
|
||||
```bash
|
||||
sudo vim /etc/systemd/system/firefish.service
|
||||
```
|
||||
|
||||
10. Firefish のサービスを有効化・起動する
|
||||
|
||||
```bash
|
||||
sudo systemctl enable --now firefish
|
||||
```
|
||||
|
||||
これで `http://localhost:3000` で Web クライアントが動くので、リバースプロキシやファイヤーウォールを設定して外部からアクセス可能にすればよいです。その設定には[私のブログ](https://blog.naskya.net/post/6kic0tebueju/)や[本家 Firefish の README](https://git.joinfirefish.org/firefish/firefish#-getting-started)が参考になるかもしれません。
|
||||
|
||||
正常にインストールできなかった場合には自力で解決しようとせず、[私にコマンドの実行ログを送ってください](https://code.naskya.net/naskya/firefish/source-by/main/docs/trouble_shooting.md#私にコマンドの実行ログを送る)。
|
||||
|
||||
## コンテナイメージを用いる
|
||||
|
||||
実行環境として [Podman](https://podman.io/) と [Docker](https://www.docker.com/) をサポートしています。Docker を使う場合には以下の `podman`, `podman-compose`, `--podman` をそれぞれ `docker`, `docker-compose`, `--docker` に読み替えてください。
|
||||
|
||||
x86_64 アーキテクチャの Linux のマシン上では、[`registry.code.naskya.net/naskya/firefish`](https://view.registry.code.naskya.net/naskya/firefish) に上げられている [OCI コンテナイメージ](https://opencontainers.org/)を利用できます。それ以外の環境で使うには、自分でコンテナイメージをビルドする必要があります。
|
||||
|
||||
1. このリポジトリを複製し、リポジトリのディレクトリに移る
|
||||
|
||||
```bash
|
||||
git clone --branch=main https://code.naskya.net/naskya/firefish
|
||||
cd firefish
|
||||
```
|
||||
|
||||
2. 設定ファイルのテンプレートを複製する
|
||||
|
||||
```bash
|
||||
cp docker-compose.example.yml docker-compose.yml
|
||||
cp .config/docker.example.env .config/docker.env
|
||||
cp .config/example.yml .config/default.yml
|
||||
```
|
||||
|
||||
3. PostgreSQL のユーザー名・データベース名・パスワードを決めて `./config/docker.env` に書く
|
||||
|
||||
```bash
|
||||
vim .config/docker.env
|
||||
```
|
||||
|
||||
4. `.config/default.yml` を編集する
|
||||
|
||||
```bash
|
||||
vim .config/default.yml
|
||||
```
|
||||
|
||||
`url` という項目を `example.com` から使いたいドメイン名に変更する
|
||||
|
||||
```yaml
|
||||
# Final accessible URL seen by a user.
|
||||
url: https://example.com/
|
||||
```
|
||||
|
||||
データベースの設定を変える(データベース名・ユーザー名・パスワードはそれぞれさっき `.config/docker.env` に書いた `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`)
|
||||
|
||||
```yaml
|
||||
db:
|
||||
host: localhost # ここを firefish_db に変える
|
||||
port: 5432 # 変えない
|
||||
|
||||
db: firefish_db # ここをデータベース名に変える
|
||||
|
||||
user: firefish # ここをデータベースのユーザー名に変える
|
||||
pass: very_strong_password # ここをデータベースのパスワードに変える
|
||||
```
|
||||
|
||||
Redis の設定を変える
|
||||
|
||||
```yaml
|
||||
redis:
|
||||
host: localhost # ここを firefish_redis に変える
|
||||
```
|
||||
|
||||
5. コンテナイメージをダウンロードまたはビルドする
|
||||
|
||||
```bash
|
||||
./update.sh --install --podman
|
||||
```
|
||||
|
||||
6. データベースのコンテナのみを起動する
|
||||
|
||||
```bash
|
||||
podman-compose up db --detach
|
||||
```
|
||||
|
||||
7. PGroonga を有効にする(`firefish` と `firefish_db` はそれぞれ自分が決めたユーザー名とデータベース名に変えて実行する)
|
||||
|
||||
```bash
|
||||
podman-compose exec db psql --user=firefish --dbname=firefish_db --command='CREATE EXTENSION pgroonga;'
|
||||
```
|
||||
|
||||
8. Firefish を起動する
|
||||
|
||||
```bash
|
||||
podman-compose up --detach
|
||||
```
|
||||
|
||||
これで `http://localhost:3000` で Web クライアントが動くので、リバースプロキシやファイヤーウォールを設定して外部からアクセス可能にすればよいです。その設定には[私のブログ](https://blog.naskya.net/post/6kic0tebueju/)や[本家 Firefish の README](https://git.joinfirefish.org/firefish/firefish#-getting-started)が参考になるかもしれません。
|
||||
|
||||
正常にインストールできなかった場合には自力で解決しようとせず、[私にコマンドの実行ログを送ってください](https://code.naskya.net/naskya/firefish/source-by/main/docs/trouble_shooting.md#私にコマンドの実行ログを送る)。
|
175
docs/migrate.md
Normal file
175
docs/migrate.md
Normal file
|
@ -0,0 +1,175 @@
|
|||
# このフォークから本家版に移行する
|
||||
|
||||
## サーバーに Firefish を直接インストールしている場合
|
||||
|
||||
1. サーバーを停止する
|
||||
|
||||
```bash
|
||||
sudo systemctl stop firefish
|
||||
```
|
||||
|
||||
2. サーバーのバックアップを取る
|
||||
|
||||
3. Firefish がインストールされているディレクトリ (e.g., `/home/firefish/firefish`) の親ディレクトリ (e.g., `/home/firefish`) に移動する
|
||||
|
||||
```bash
|
||||
cd /home/firefish
|
||||
```
|
||||
|
||||
4. Firefish がインストールされているディレクトリ (e.g., `./firefish`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv firefish firefish.old
|
||||
```
|
||||
|
||||
5. 元々 Firefish がインストールされていたディレクトリ (e.g., `./firefish`) と同じ名前でこのリポジトリをクローンする
|
||||
|
||||
```bash
|
||||
git clone --branch=main https://code.naskya.net/naskya/firefish firefish
|
||||
```
|
||||
|
||||
6. 必要なファイルを元のディレクトリからコピーする
|
||||
|
||||
```bash
|
||||
rm -rf firefish/files firefish/custom firefish/.config
|
||||
cp -r firefish.old/files firefish
|
||||
cp -r firefish.old/custom firefish
|
||||
cp -r firefish.old/.config firefish
|
||||
```
|
||||
|
||||
7. 全文検索エンジン(Meilisearch, Sonic, Elasticsearch のいずれか)を使用している場合には、`.config/default.yml` からその設定を削除またはコメントアウトする
|
||||
|
||||
先頭に `#` をつけると設定をコメントアウトできます。
|
||||
|
||||
```yaml
|
||||
#sonic:
|
||||
# host: localhost
|
||||
# port: 1491
|
||||
# auth: SecretPassword
|
||||
# collection: notes
|
||||
# bucket: default
|
||||
```
|
||||
|
||||
全文検索エンジンは停止またはアンインストールしてしまってよいです。本家の Firefish に戻るつもりがあるなら停止を、そうでなければアンインストールをおすすめします。
|
||||
|
||||
停止コマンドの例
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now sonic
|
||||
```
|
||||
|
||||
8. PostgreSQL のバージョンを確認する
|
||||
|
||||
```bash
|
||||
psql --version
|
||||
```
|
||||
|
||||
9. PGroonga をインストールする
|
||||
|
||||
コマンドの例(詳しくは[この投稿](https://post.naskya.net/notes/9ldi29amfanomef5)を参考にしてください)
|
||||
|
||||
```bash
|
||||
sudo apt install -y software-properties-common
|
||||
sudo add-apt-repository -y universe
|
||||
sudo add-apt-repository -y ppa:groonga/ppa
|
||||
sudo apt install -y wget lsb-release
|
||||
wget https://packages.groonga.org/ubuntu/groonga-apt-source-latest-$(lsb_release --codename --short).deb
|
||||
sudo apt install -y -V ./groonga-apt-source-latest-$(lsb_release --codename --short).deb
|
||||
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release --codename --short)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo apt update
|
||||
sudo apt install -y -V postgresql-16-pgdg-pgroonga
|
||||
```
|
||||
|
||||
10. `.config/default.yml` に書かれているデータベースの名前を確認する(以下の例では `firefish_db`)
|
||||
|
||||
```yaml
|
||||
db:
|
||||
host: localhost
|
||||
port: 5432
|
||||
db: firefish_db # これ
|
||||
```
|
||||
|
||||
11. 以下のコマンドを実行して PGroonga の拡張機能を有効にする(`firefish_db` の部分は自分のデータベース名に変えて実行)
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql --command="CREATE EXTENSION pgroonga;" --dbname=firefish_db
|
||||
```
|
||||
|
||||
12. 新しい Firefish のディレクトリに入ってビルドする
|
||||
|
||||
```bash
|
||||
cd firefish
|
||||
./update.sh --install --native
|
||||
```
|
||||
|
||||
13. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
sudo systemctl start firefish
|
||||
```
|
||||
|
||||
14. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf firefish.old
|
||||
```
|
||||
|
||||
## コンテナで Firefish を動かしている場合
|
||||
|
||||
Docker を使う場合には以下の `podman`, `podman-compose`, `--podman` をそれぞれ `docker`, `docker-compose`, `--docker` に読み替えてください。
|
||||
|
||||
1. サーバーを停止し、バックアップを取る
|
||||
2. Firefish がインストールされているディレクトリ (e.g., `/home/firefish/firefish`) の親ディレクトリ (e.g., `/home/firefish`) に移動する
|
||||
|
||||
```bash
|
||||
cd /home/firefish
|
||||
```
|
||||
|
||||
3. Firefish がインストールされているディレクトリ (e.g., `./firefish`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv firefish firefish.old
|
||||
```
|
||||
|
||||
4. 元々 Firefish がインストールされていたディレクトリ (e.g., `./firefish`) と同じ名前でこのリポジトリをクローンする
|
||||
|
||||
```bash
|
||||
git clone --branch=main https://code.naskya.net/naskya/firefish firefish
|
||||
```
|
||||
|
||||
5. 必要なファイルを元のディレクトリからコピーする
|
||||
|
||||
```bash
|
||||
rm -rf firefish/files firefish/custom firefish/.config
|
||||
cp -r firefish.old/files firefish
|
||||
cp -r firefish.old/custom firefish
|
||||
cp -r firefish.old/.config firefish
|
||||
```
|
||||
|
||||
6. 以下のコマンドを実行して PGroonga を有効にする(`firefish` と `firefish_db` はそれぞれ `.config/docker.env` や `.config/default.yml` に書いた PostgreSQL のユーザー名とデータベース名に置き換える)
|
||||
|
||||
```bash
|
||||
podman-compose up db --detach
|
||||
podman-compose exec db psql --command='CREATE EXTENSION pgroonga;' --user=firefish --dbname=firefish_db
|
||||
```
|
||||
|
||||
7. コンテナイメージをダウンロードまたはビルドする
|
||||
|
||||
```bash
|
||||
./update.sh --install --podman
|
||||
```
|
||||
|
||||
8. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
podman-compose up --detach
|
||||
```
|
||||
|
||||
9. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf firefish.old
|
||||
```
|
208
docs/migrate_back.md
Normal file
208
docs/migrate_back.md
Normal file
|
@ -0,0 +1,208 @@
|
|||
# このフォークから本家版に移行する
|
||||
|
||||
## サーバーに Firefish を直接インストールしている場合
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. サーバーを停止する
|
||||
|
||||
```bash
|
||||
sudo systemctl stop firefish
|
||||
```
|
||||
|
||||
3. Firefish がインストールされているディレクトリ (e.g., `/home/firefish/firefish`) へ移動する
|
||||
|
||||
```bash
|
||||
cd /home/firefish/firefish
|
||||
```
|
||||
|
||||
4. 最新版にアップデートする
|
||||
|
||||
```bash
|
||||
./update.sh
|
||||
```
|
||||
|
||||
5. `.config/default.yml` に書かれているデータベースの名前を確認する(以下の例では `firefish_db`)
|
||||
|
||||
```yaml
|
||||
db:
|
||||
host: localhost
|
||||
port: 5432
|
||||
db: firefish_db # これ
|
||||
```
|
||||
|
||||
6. 次のコマンドでデータベースをいじる前に、そのコマンドが正常に動作するか確認する(`firefish_db` の部分は自分のデータベース名に変更する)
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -u postgres psql --echo-all --set='ON_ERROR_STOP=1' --dbname=firefish_db
|
||||
```
|
||||
|
||||
最後の行が `ROLLBACK` で終わっていれば問題ありません。そうでない場合には[私にコマンドの実行ログを送ってください](https://code.naskya.net/naskya/firefish/source-by/main/docs/trouble_shooting.md#私にコマンドの実行ログを送る)。
|
||||
|
||||
7. このフォークで加えられたデータベースへの変更を実際に取り消す(`firefish_db` の部分は自分のデータベース名に変更する)
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql --file=neko/revert.sql --dbname=firefish_db
|
||||
```
|
||||
|
||||
8. PGroonga をアンインストールする
|
||||
|
||||
コマンドの例
|
||||
|
||||
```bash
|
||||
sudo apt purge --remove postgresql-16-pgdg-pgroonga
|
||||
sudo add-apt-repository --remove ppa:groonga/ppa
|
||||
sudo apt-key del ACCC4CF8
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
9. Firefish がインストールされているディレクトリの親ディレクトリ (e.g., `/home/firefish`) に行く
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
```
|
||||
|
||||
10. Firefish がインストールされているディレクトリ (e.g., `./firefish`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv firefish firefish.old
|
||||
```
|
||||
|
||||
11. Firefish がインストールされているディレクトリと同じ名前で本家版の Firefish を clone する
|
||||
|
||||
```bash
|
||||
git clone https://git.joinfirefish.org/firefish/firefish.git firefish
|
||||
```
|
||||
|
||||
12. 必要なファイルをコピーする
|
||||
|
||||
```bash
|
||||
rm -rf firefish/files firefish/custom firefish/.config
|
||||
cp -r firefish.old/files firefish
|
||||
cp -r firefish.old/custom firefish
|
||||
cp -r firefish.old/.config firefish
|
||||
```
|
||||
|
||||
13. 新しい Firefish のディレクトリ (e.g., `./firefish`) に入り、`develop` ブランチに行く(実際には既に `develop` にいるはず)
|
||||
|
||||
```bash
|
||||
cd firefish
|
||||
git checkout develop
|
||||
```
|
||||
|
||||
14. Firefish をビルドする
|
||||
|
||||
```bash
|
||||
corepack prepare pnpm@latest --activate
|
||||
pnpm install
|
||||
NODE_ENV=production pnpm run build
|
||||
pnpm run migrate
|
||||
```
|
||||
|
||||
15. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
sudo systemctl start firefish
|
||||
```
|
||||
|
||||
16. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf firefish.old
|
||||
```
|
||||
|
||||
## コンテナで Firefish を動かしている場合
|
||||
|
||||
Docker を使う場合には以下の `podman`, `podman-compose`, `--podman` をそれぞれ `docker`, `docker-compose`, `--docker` に読み替えてください。
|
||||
|
||||
1. サーバーのバックアップを取る
|
||||
2. Firefish がインストールされているディレクトリ (e.g., `/home/firefish/firefish`) へ移動する
|
||||
|
||||
```bash
|
||||
cd /home/firefish/firefish
|
||||
```
|
||||
|
||||
3. 最新版にアップデートする
|
||||
|
||||
```bash
|
||||
./update.sh --podman
|
||||
```
|
||||
|
||||
4. 一度サーバーを再起動し、自分のサーバーが起動したことを Web から確認したら再度停止してデータベースのコンテナのみを起動する
|
||||
|
||||
```bash
|
||||
podman-compose down
|
||||
podman-compose up --detach
|
||||
# 少し待って、サーバーが起動したことを確認する
|
||||
podman-compose down
|
||||
podman-compose up db --detach
|
||||
```
|
||||
|
||||
5. `.config/docker.env` に書かれているユーザー名とデータベース名を確認する(以下の例では `firefish_db`)
|
||||
|
||||
```env
|
||||
# db settings
|
||||
POSTGRES_PASSWORD=very_strong_password
|
||||
POSTGRES_USER=firefish # これがユーザー名
|
||||
POSTGRES_DB=firefish_db # これがデータベース名
|
||||
```
|
||||
|
||||
6. 次のコマンドでデータベースをいじる前に、そのコマンドが正常に動作するか確認する(`firefish` と `firefish_db` の部分は自分のユーザー名とデータベース名に変更する)
|
||||
|
||||
```bash
|
||||
podman-compose exec db psql --user=firefish --dbname=firefish_db --echo-all --set='ON_ERROR_STOP=1' --command="$(printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)")"
|
||||
```
|
||||
|
||||
最後の行が `ROLLBACK` で終わっていれば問題ありません。そうでない場合には[私にコマンドの実行ログを送ってください](https://code.naskya.net/naskya/firefish/source-by/main/docs/trouble_shooting.md#私にコマンドの実行ログを送る)。
|
||||
|
||||
7. このフォークで加えられたデータベースへの変更を実際に取り消す(`mk1` の部分は自分のデータベース名に変更する)
|
||||
|
||||
```bash
|
||||
podman-compose exec db psql --user=firefish --dbname=firefish_db --command="$(cat neko/revert.sql)"
|
||||
```
|
||||
|
||||
8. Firefish がインストールされているディレクトリの親ディレクトリ (e.g., `/home/firefish`) に行く
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
```
|
||||
|
||||
9. Firefish がインストールされているディレクトリ (e.g., `./firefish`) の名前を変える
|
||||
|
||||
```bash
|
||||
mv firefish firefish.old
|
||||
```
|
||||
|
||||
10. Firefish がインストールされているディレクトリと同じ名前で本家版の Firefish を clone する
|
||||
|
||||
```bash
|
||||
git clone https://git.joinfirefish.org/firefish/firefish.git firefish
|
||||
```
|
||||
|
||||
11. 必要なファイルをコピーする
|
||||
|
||||
```bash
|
||||
rm -rf firefish/files firefish/custom firefish/.config
|
||||
cp -r firefish.old/files firefish
|
||||
cp -r firefish.old/custom firefish
|
||||
cp -r firefish.old/.config firefish
|
||||
```
|
||||
|
||||
12. 新しい Firefish のディレクトリ (e.g., `./firefish`) に入る
|
||||
|
||||
```bash
|
||||
cd firefish
|
||||
```
|
||||
|
||||
13. サーバーを起動して動作を確認する
|
||||
|
||||
```bash
|
||||
podman-compose up --detach
|
||||
```
|
||||
|
||||
14. 元々 Firefish がインストールされていたディレクトリを削除する
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
rm -rf firefish.old
|
||||
```
|
35
docs/trouble_shooting.md
Normal file
35
docs/trouble_shooting.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
# トラブルシュート
|
||||
|
||||
## 私にコマンドの実行ログを送る
|
||||
|
||||
実行したいコマンドの後ろに `|& tee /tmp/fflog` をつけてコマンドを実行します。例えば実行したいコマンドが `./update.sh` ならば
|
||||
|
||||
```bash
|
||||
./update.sh |& tee /tmp/fflog
|
||||
```
|
||||
|
||||
とし、実行したいコマンドが
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -u postgres psql --echo-all --set='ON_ERROR_STOP=1' --dbname=firefish_db
|
||||
```
|
||||
|
||||
ならば
|
||||
|
||||
```bash
|
||||
printf 'BEGIN;\n%s\nROLLBACK;' "$(cat neko/revert.sql)" | sudo -u postgres psql --echo-all --set='ON_ERROR_STOP=1' --dbname=firefish_db |& tee /tmp/fflog
|
||||
```
|
||||
|
||||
とします。
|
||||
|
||||
するとコマンドの実行ログが `/tmp/fflog` に保存されるので、保存されたテキスト全体をサーバーの OS などの環境の情報とともに[私](https://post.naskya.net/@dev)に送ってください。
|
||||
|
||||
ログのうちの参考になりそうだと思った一部だけを抜粋して送ることは絶対にしないでください。必要な情報が欠落していてもう一度全体を送り直してもらうことになったり、私が対処方法の判断を誤ったりする可能性が高まったりします。
|
||||
|
||||
テキストが一つの投稿に収まる長さの場合はコードブロックの記法(``` で囲む)を用いて投稿してもらってよいです。ログが一投稿に収まらない長さの場合は [Pastebin](https://pastebin.com/) などのサービスを使って共有してください。投稿にログファイルを直接添付して送ることはしないでください。
|
||||
|
||||
ログを私に送ったら `/tmp/fflog` は削除してよいです。
|
||||
|
||||
```bash
|
||||
rm /tmp/fflog
|
||||
```
|
13
docs/update.md
Normal file
13
docs/update.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# アップデート方法
|
||||
|
||||
必ず添付されているアップデートスクリプト (`update.sh`) を用いてアップデートしてください。それ以外のアップデート方法はサポートされていません。
|
||||
|
||||
1. サーバーを停止し、バックアップを取る
|
||||
2. Firefish のリポジトリのディレクトリに移動する
|
||||
3. アップデートスクリプトを実行し、表示される指示に従う
|
||||
|
||||
```bash
|
||||
./update.sh
|
||||
```
|
||||
|
||||
正常にアップデートできなかった場合には自力で解決しようとせず、[私にコマンドの実行ログを送ってください](https://code.naskya.net/naskya/firefish/source-by/main/docs/trouble_shooting.md#私にコマンドの実行ログを送る)。
|
|
@ -266,9 +266,21 @@ if (!nativeBinding) {
|
|||
}
|
||||
|
||||
const {
|
||||
EnvConfig,
|
||||
readEnvironmentConfig,
|
||||
readServerConfig,
|
||||
stringToAcct,
|
||||
acctToString,
|
||||
nativeRandomStr,
|
||||
getFullApAccount,
|
||||
isSelfHost,
|
||||
extractHost,
|
||||
toPuny,
|
||||
toPunyOptional,
|
||||
convertToHiddenPost,
|
||||
sqlLikeEscape,
|
||||
safeForSql,
|
||||
formatMilliseconds,
|
||||
genString,
|
||||
IdConvertType,
|
||||
convertId,
|
||||
nativeGetTimestamp,
|
||||
|
@ -276,9 +288,21 @@ const {
|
|||
nativeInitIdGenerator,
|
||||
} = nativeBinding;
|
||||
|
||||
module.exports.EnvConfig = EnvConfig;
|
||||
module.exports.readEnvironmentConfig = readEnvironmentConfig;
|
||||
module.exports.readServerConfig = readServerConfig;
|
||||
module.exports.stringToAcct = stringToAcct;
|
||||
module.exports.acctToString = acctToString;
|
||||
module.exports.nativeRandomStr = nativeRandomStr;
|
||||
module.exports.getFullApAccount = getFullApAccount;
|
||||
module.exports.isSelfHost = isSelfHost;
|
||||
module.exports.extractHost = extractHost;
|
||||
module.exports.toPuny = toPuny;
|
||||
module.exports.toPunyOptional = toPunyOptional;
|
||||
module.exports.convertToHiddenPost = convertToHiddenPost;
|
||||
module.exports.sqlLikeEscape = sqlLikeEscape;
|
||||
module.exports.safeForSql = safeForSql;
|
||||
module.exports.formatMilliseconds = formatMilliseconds;
|
||||
module.exports.genString = genString;
|
||||
module.exports.IdConvertType = IdConvertType;
|
||||
module.exports.convertId = convertId;
|
||||
module.exports.nativeGetTimestamp = nativeGetTimestamp;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# shellcheck disable=SC2148
|
||||
|
||||
color() {
|
||||
if [ -t 1 ]; then
|
||||
tput setaf "${1:-7}"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"clean": "pnpm node ./scripts/clean-built.mjs",
|
||||
"clean-cargo": "pnpm node ./scripts/clean-cargo.mjs",
|
||||
"clean-npm": "pnpm node ./scripts/clean-npm.mjs",
|
||||
"clean-all": "pnpm run clean && pnpm run claen-cargo && pnpm run clean-npm",
|
||||
"clean-all": "pnpm run clean && pnpm run clean-cargo && pnpm run clean-npm",
|
||||
"cleanall": "pnpm run clean-all"
|
||||
},
|
||||
"resolutions": {
|
||||
|
|
3
packages/backend/native-utils/Cargo.lock
generated
3
packages/backend/native-utils/Cargo.lock
generated
|
@ -1436,6 +1436,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"cuid2",
|
||||
"derive_more",
|
||||
"idna",
|
||||
"jsonschema",
|
||||
"napi",
|
||||
"napi-build",
|
||||
|
@ -1448,8 +1449,10 @@ dependencies = [
|
|||
"sea-orm",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ members = ["migration"]
|
|||
|
||||
[features]
|
||||
default = []
|
||||
napi = ["dep:napi", "dep:napi-derive"]
|
||||
napi = ["dep:napi-derive"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
|
@ -19,6 +19,7 @@ cfg-if = "1.0.0"
|
|||
chrono = "0.4.31"
|
||||
cuid2 = "0.1.2"
|
||||
derive_more = "0.99.17"
|
||||
idna = "0.5.0"
|
||||
jsonschema = "0.17.1"
|
||||
once_cell = "1.19.0"
|
||||
parse-display = "0.8.2"
|
||||
|
@ -27,12 +28,14 @@ schemars = { version = "0.8.16", features = ["chrono"] }
|
|||
sea-orm = { version = "0.12.10", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
|
||||
serde = { version = "1.0.193", features = ["derive"] }
|
||||
serde_json = "1.0.108"
|
||||
serde_yaml = "0.9.29"
|
||||
thiserror = "1.0.52"
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
url = "2.5.0"
|
||||
utoipa = "4.1.0"
|
||||
|
||||
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
||||
napi = { version = "2.14.1", default-features = false, features = ["napi9", "tokio_rt"], optional = true }
|
||||
napi = { version = "2.14.1", default-features = false, features = ["napi9", "tokio_rt"] }
|
||||
napi-derive = { version = "2.14.5", optional = true }
|
||||
basen = "0.1.0"
|
||||
|
||||
|
|
28
packages/backend/native-utils/src/config/environment.rs
Normal file
28
packages/backend/native-utils/src/config/environment.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub struct EnvConfig {
|
||||
pub only_queue: bool,
|
||||
pub only_server: bool,
|
||||
pub no_daemons: bool,
|
||||
pub disable_clustering: bool,
|
||||
pub verbose: bool,
|
||||
pub with_log_time: bool,
|
||||
pub quiet: bool,
|
||||
pub slow: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn read_environment_config() -> EnvConfig {
|
||||
let node_env = std::env::var("NODE_ENV").unwrap_or_default().to_lowercase();
|
||||
let is_testing = node_env == "test" || node_env == "testing";
|
||||
|
||||
EnvConfig {
|
||||
only_queue: std::env::var("MK_ONLY_QUEUE").is_ok(),
|
||||
only_server: std::env::var("MK_ONLY_SERVER").is_ok(),
|
||||
no_daemons: is_testing || std::env::var("MK_NO_DAEMONS").is_ok(),
|
||||
disable_clustering: is_testing || std::env::var("MK_DISABLE_CLUSTERING").is_ok(),
|
||||
verbose: std::env::var("MK_VERBOSE").is_ok(),
|
||||
with_log_time: std::env::var("MK_WITH_LOG_TIME").is_ok(),
|
||||
quiet: is_testing || std::env::var("MK_QUIET").is_ok(),
|
||||
slow: std::env::var("MK_SLOW").is_ok(),
|
||||
}
|
||||
}
|
2
packages/backend/native-utils/src/config/mod.rs
Normal file
2
packages/backend/native-utils/src/config/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod environment;
|
||||
pub mod server;
|
54
packages/backend/native-utils/src/config/server.rs
Normal file
54
packages/backend/native-utils/src/config/server.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use serde::Deserialize;
|
||||
use serde_yaml;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(object))]
|
||||
pub struct ServerConfig {
|
||||
pub url: String,
|
||||
pub db: DbConfig,
|
||||
pub redis: RedisConfig,
|
||||
pub cache_server: Option<RedisConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(object))]
|
||||
pub struct DbConfig {
|
||||
pub host: String,
|
||||
pub port: u32,
|
||||
pub db: String,
|
||||
pub user: String,
|
||||
pub pass: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(object))]
|
||||
pub struct RedisConfig {
|
||||
pub host: String,
|
||||
pub port: u32,
|
||||
pub user: Option<String>,
|
||||
pub pass: Option<String>,
|
||||
pub tls: Option<TlsConfig>,
|
||||
#[serde(default)]
|
||||
pub db: u32,
|
||||
#[serde(default)]
|
||||
pub prefix: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(object))]
|
||||
pub struct TlsConfig {
|
||||
pub host: String,
|
||||
pub reject_unauthorized: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn read_server_config() -> ServerConfig {
|
||||
let cwd = env::current_dir().unwrap();
|
||||
let yml = fs::File::open(cwd.join("../../.config/default.yml"))
|
||||
.expect("Failed to open '.config/default.yml'");
|
||||
serde_yaml::from_reader(yml).expect("Failed to parse yaml")
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod config;
|
||||
pub mod database;
|
||||
pub mod macros;
|
||||
pub mod model;
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Default)]
|
||||
#[sea_orm(table_name = "antenna_note")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: String,
|
||||
#[sea_orm(column_name = "noteId")]
|
||||
pub note_id: String,
|
||||
#[sea_orm(column_name = "antennaId")]
|
||||
pub antenna_id: String,
|
||||
pub read: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::antenna::Entity",
|
||||
from = "Column::AntennaId",
|
||||
to = "super::antenna::Column::Id",
|
||||
on_update = "NoAction",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Antenna,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::note::Entity",
|
||||
from = "Column::NoteId",
|
||||
to = "super::note::Column::Id",
|
||||
on_update = "NoAction",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Note,
|
||||
}
|
||||
|
||||
impl Related<super::antenna::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Antenna.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::note::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Note.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -51,6 +51,7 @@ pub mod registration_ticket;
|
|||
pub mod registry_item;
|
||||
pub mod relay;
|
||||
pub mod renote_muting;
|
||||
pub mod reply_muting;
|
||||
pub mod sea_orm_active_enums;
|
||||
pub mod signin;
|
||||
pub mod sw_subscription;
|
||||
|
|
|
@ -61,7 +61,6 @@ pub struct Model {
|
|||
pub thread_id: Option<String>,
|
||||
#[sea_orm(column_name = "updatedAt")]
|
||||
pub updated_at: Option<DateTimeWithTimeZone>,
|
||||
#[sea_orm(column_name = "lang")]
|
||||
pub lang: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ pub use super::registration_ticket::Entity as RegistrationTicket;
|
|||
pub use super::registry_item::Entity as RegistryItem;
|
||||
pub use super::relay::Entity as Relay;
|
||||
pub use super::renote_muting::Entity as RenoteMuting;
|
||||
pub use super::reply_muting::Entity as ReplyMuting;
|
||||
pub use super::signin::Entity as Signin;
|
||||
pub use super::sw_subscription::Entity as SwSubscription;
|
||||
pub use super::used_username::Entity as UsedUsername;
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.10
|
||||
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "reply_muting")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: String,
|
||||
#[sea_orm(column_name = "createdAt")]
|
||||
pub created_at: DateTimeWithTimeZone,
|
||||
#[sea_orm(column_name = "muteeId")]
|
||||
pub mutee_id: String,
|
||||
#[sea_orm(column_name = "muterId")]
|
||||
pub muter_id: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
|
@ -1,13 +1,10 @@
|
|||
use napi_derive::napi;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
#[napi(object)]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(object))]
|
||||
pub struct Acct {
|
||||
pub username: String,
|
||||
pub host: Option<String>,
|
||||
}
|
||||
|
||||
#[napi]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn string_to_acct(acct: String) -> Acct {
|
||||
let split: Vec<&str> = if let Some(stripped) = acct.strip_prefix('@') {
|
||||
stripped
|
||||
|
@ -27,7 +24,7 @@ pub fn string_to_acct(acct: String) -> Acct {
|
|||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn acct_to_string(acct: Acct) -> String {
|
||||
match acct.host {
|
||||
Some(host) => format!("{}@{}", acct.username, host),
|
||||
|
|
64
packages/backend/native-utils/src/util/convert_host.rs
Normal file
64
packages/backend/native-utils/src/util/convert_host.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use crate::config::server::read_server_config;
|
||||
use idna;
|
||||
use url::Url;
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn get_full_ap_account(username: String, host: Option<String>) -> String {
|
||||
if host.is_none() {
|
||||
format!("{}@{}", username, extract_host(read_server_config().url))
|
||||
} else {
|
||||
format!("{}@{}", username, to_puny(host.unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn is_self_host(host: Option<String>) -> bool {
|
||||
if let Some(x) = host {
|
||||
extract_host(read_server_config().url) == to_puny(x)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn extract_host(uri: String) -> String {
|
||||
to_puny(
|
||||
Url::parse(uri.as_str())
|
||||
.expect("Invalid uri")
|
||||
.host_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn to_puny(host: String) -> String {
|
||||
idna::domain_to_ascii(&host).expect("Failed to encode the host to punycode")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn to_puny_optional(host: Option<String>) -> Option<String> {
|
||||
host.map(to_puny)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{extract_host, to_puny};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn extract_host_test() {
|
||||
assert_eq!(
|
||||
extract_host("https://git.joinfirefish.org/firefish/firefish.git".to_string()),
|
||||
"git.joinfirefish.org".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_puny_test() {
|
||||
assert_eq!(
|
||||
to_puny("何もかも.owari.shop".to_string()),
|
||||
"xn--u8jyfb5762a.owari.shop".to_string()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
use napi;
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi(object))]
|
||||
pub struct Post {
|
||||
pub text: Option<String>,
|
||||
pub cw: Option<String>,
|
||||
pub local_only: bool,
|
||||
pub created_at: napi::JsDate,
|
||||
/// FIXME: introduce enum type (and remove "hiddensomething" visibility if possible)
|
||||
pub visibility: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn convert_to_hidden_post(original_post: Post) -> Post {
|
||||
Post {
|
||||
text: match original_post.text {
|
||||
Some(s) if !s.is_empty() => Some(s),
|
||||
_ => None,
|
||||
},
|
||||
cw: original_post.cw,
|
||||
local_only: original_post.local_only,
|
||||
created_at: original_post.created_at,
|
||||
visibility: format!("hidden{}", original_post.visibility),
|
||||
}
|
||||
}
|
41
packages/backend/native-utils/src/util/escape_sql.rs
Normal file
41
packages/backend/native-utils/src/util/escape_sql.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn sql_like_escape(src: String) -> String {
|
||||
src.replace('%', r"\%").replace('_', r"\_")
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn safe_for_sql(src: String) -> bool {
|
||||
!src.contains([
|
||||
'\0', '\x08', '\x09', '\x1a', '\n', '\r', '"', '\'', '\\', '%',
|
||||
])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::{safe_for_sql, sql_like_escape};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn sql_like_escape_test() {
|
||||
assert_eq!(sql_like_escape("".to_string()), "".to_string());
|
||||
assert_eq!(sql_like_escape("abc".to_string()), "abc".to_string());
|
||||
assert_eq!(sql_like_escape("a%bc".to_string()), r"a\%bc".to_string());
|
||||
assert_eq!(
|
||||
sql_like_escape("a呼%吸bc".to_string()),
|
||||
r"a呼\%吸bc".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
sql_like_escape("_اللغة العربية".to_string()),
|
||||
r"\_اللغة العربية".to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn safe_for_sql_test() {
|
||||
assert!(safe_for_sql("123".to_string()));
|
||||
assert!(safe_for_sql("人間".to_string()));
|
||||
assert!(!safe_for_sql("人間\x09".to_string()));
|
||||
assert!(!safe_for_sql("abc\ndef".to_string()));
|
||||
assert!(!safe_for_sql("%something%".to_string()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/// Convert milliseconds to human readable string
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn format_milliseconds(milliseconds: i32) -> String {
|
||||
let mut seconds = milliseconds / 1000;
|
||||
let mut minutes = seconds / 60;
|
||||
let mut hours = minutes / 60;
|
||||
let days = hours / 24;
|
||||
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 24;
|
||||
|
||||
let mut buf = Vec::<String>::new();
|
||||
|
||||
if days > 0 {
|
||||
buf.push(format!("{} day(s)", days));
|
||||
}
|
||||
if hours > 0 {
|
||||
buf.push(format!("{} hour(s)", hours));
|
||||
}
|
||||
if minutes > 0 {
|
||||
buf.push(format!("{} minute(s)", minutes));
|
||||
}
|
||||
if seconds > 0 {
|
||||
buf.push(format!("{} second(s)", seconds));
|
||||
}
|
||||
|
||||
buf.join(", ")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use super::format_milliseconds;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn format_milliseconds_test() {
|
||||
assert_eq!(format_milliseconds(1000), "1 second(s)".to_string());
|
||||
assert_eq!(
|
||||
format_milliseconds(1387938),
|
||||
"23 minute(s), 7 second(s)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format_milliseconds(34200457),
|
||||
"9 hour(s), 30 minute(s)".to_string()
|
||||
);
|
||||
assert_eq!(
|
||||
format_milliseconds(998244353),
|
||||
"11 day(s), 13 hour(s), 17 minute(s), 24 second(s)".to_string()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
pub mod acct;
|
||||
pub mod convert_host;
|
||||
pub mod convert_to_hidden_post;
|
||||
pub mod escape_sql;
|
||||
pub mod format_milliseconds;
|
||||
pub mod id;
|
||||
pub mod random;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||
|
||||
/// Generate random string based on [thread_rng] and [Alphanumeric].
|
||||
#[cfg_attr(feature = "napi", napi_derive::napi)]
|
||||
pub fn gen_string(length: u16) -> String {
|
||||
thread_rng()
|
||||
.sample_iter(Alphanumeric)
|
||||
|
@ -9,12 +10,6 @@ pub fn gen_string(length: u16) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(feature = "napi")]
|
||||
#[napi_derive::napi]
|
||||
pub fn native_random_str(length: u16) -> String {
|
||||
gen_string(length)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_test {
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
|
|
|
@ -3,7 +3,7 @@ import chalk from "chalk";
|
|||
import Xev from "xev";
|
||||
|
||||
import Logger from "@/services/logger.js";
|
||||
import { envOption } from "../env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
|
||||
// for typeorm
|
||||
import "reflect-metadata";
|
||||
|
|
|
@ -10,7 +10,7 @@ import semver from "semver";
|
|||
import Logger from "@/services/logger.js";
|
||||
import loadConfig from "@/config/load.js";
|
||||
import type { Config } from "@/config/types.js";
|
||||
import { envOption } from "@/env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
import { showMachineInfo } from "@/misc/show-machine-info.js";
|
||||
import { db, initDb } from "@/db/postgre.js";
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import load from "./load.js";
|
||||
import { readEnvironmentConfig } from "native-utils/built/index.js";
|
||||
|
||||
export default load();
|
||||
export const envOption = readEnvironmentConfig();
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
const envOption = {
|
||||
onlyQueue: false,
|
||||
onlyServer: false,
|
||||
noDaemons: false,
|
||||
disableClustering: false,
|
||||
verbose: false,
|
||||
withLogTime: false,
|
||||
quiet: false,
|
||||
slow: false,
|
||||
};
|
||||
|
||||
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {
|
||||
if (
|
||||
process.env[
|
||||
`MK_${key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase()}`
|
||||
]
|
||||
)
|
||||
envOption[key] = true;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "test") envOption.disableClustering = true;
|
||||
if (process.env.NODE_ENV === "test") envOption.quiet = true;
|
||||
if (process.env.NODE_ENV === "test") envOption.noDaemons = true;
|
||||
|
||||
export { envOption };
|
|
@ -2,8 +2,7 @@ import type { Antenna } from "@/models/entities/antenna.js";
|
|||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { Blockings, Followings, UserProfiles } from "@/models/index.js";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import { stringToAcct } from "native-utils/built/index.js";
|
||||
import { getFullApAccount, stringToAcct } from "native-utils/built/index.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import { URL } from "node:url";
|
||||
import config from "@/config/index.js";
|
||||
import { toASCII } from "punycode";
|
||||
|
||||
export function getFullApAccount(username: string, host: string | null) {
|
||||
return host
|
||||
? `${username}@${toPuny(host)}`
|
||||
: `${username}@${toPuny(config.host)}`;
|
||||
}
|
||||
|
||||
export function isSelfHost(host: string) {
|
||||
if (host == null) return true;
|
||||
return toPuny(config.host) === toPuny(host);
|
||||
}
|
||||
|
||||
export function extractDbHost(uri: string) {
|
||||
const url = new URL(uri);
|
||||
return toPuny(url.hostname);
|
||||
}
|
||||
|
||||
export function toPuny(host: string) {
|
||||
return toASCII(host.toLowerCase());
|
||||
}
|
||||
|
||||
export function toPunyNullable(host: string | null | undefined): string | null {
|
||||
if (host == null) return null;
|
||||
return toASCII(host.toLowerCase());
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
export function convertMilliseconds(ms: number) {
|
||||
let seconds = Math.round(ms / 1000);
|
||||
let minutes = Math.round(seconds / 60);
|
||||
let hours = Math.round(minutes / 60);
|
||||
const days = Math.round(hours / 24);
|
||||
seconds %= 60;
|
||||
minutes %= 60;
|
||||
hours %= 24;
|
||||
|
||||
const result = [];
|
||||
if (days > 0) result.push(`${days} day(s)`);
|
||||
if (hours > 0) result.push(`${hours} hour(s)`);
|
||||
if (minutes > 0) result.push(`${minutes} minute(s)`);
|
||||
if (seconds > 0) result.push(`${seconds} second(s)`);
|
||||
|
||||
return result.join(", ");
|
||||
}
|
|
@ -3,7 +3,7 @@ import { Emojis } from "@/models/index.js";
|
|||
import type { Emoji } from "@/models/entities/emoji.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { Cache } from "./cache.js";
|
||||
import { isSelfHost, toPunyNullable } from "./convert-host.js";
|
||||
import { isSelfHost, toPunyOptional } from "native-utils/built/index.js";
|
||||
import { decodeReaction } from "./reaction-lib.js";
|
||||
import config from "@/config/index.js";
|
||||
import { query } from "@/prelude/url.js";
|
||||
|
@ -35,7 +35,7 @@ function normalizeHost(
|
|||
? null // 自ホスト指定
|
||||
: src || noteUserHost; // 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない)
|
||||
|
||||
host = toPunyNullable(host);
|
||||
host = toPunyOptional(host);
|
||||
|
||||
return host;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ function parseEmojiStr(emojiName: string, noteUserHost: string | null) {
|
|||
const name = match[1];
|
||||
|
||||
// ホスト正規化
|
||||
const host = toPunyNullable(normalizeHost(match[2], noteUserHost));
|
||||
const host = toPunyOptional(normalizeHost(match[2], noteUserHost));
|
||||
|
||||
return { name, host };
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
export type Post = {
|
||||
text: string | undefined;
|
||||
cw: string | null;
|
||||
localOnly: boolean;
|
||||
createdAt: Date;
|
||||
visibility: string;
|
||||
};
|
||||
|
||||
export function parse(acct: any): Post {
|
||||
return {
|
||||
text: acct.text || undefined,
|
||||
cw: acct.cw,
|
||||
localOnly: acct.localOnly,
|
||||
createdAt: new Date(acct.createdAt),
|
||||
visibility: `hidden${acct.visibility || ""}`,
|
||||
};
|
||||
}
|
||||
|
||||
export function toJson(acct: Post): string {
|
||||
return { text: acct.text, cw: acct.cw, localOnly: acct.localOnly }.toString();
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { emojiRegex } from "./emoji-regex.js";
|
||||
import { fetchMeta } from "./fetch-meta.js";
|
||||
import { Emojis } from "@/models/index.js";
|
||||
import { toPunyNullable } from "./convert-host.js";
|
||||
import { toPunyOptional } from "native-utils/built/index.js";
|
||||
import { IsNull } from "typeorm";
|
||||
|
||||
export function convertReactions(reactions: Record<string, number>) {
|
||||
|
@ -23,7 +23,7 @@ export async function toDbReaction(
|
|||
): Promise<string> {
|
||||
if (!reaction) return (await fetchMeta()).defaultReaction;
|
||||
|
||||
reacterHost = toPunyNullable(reacterHost);
|
||||
reacterHost = toPunyOptional(reacterHost);
|
||||
|
||||
if (reaction.includes("❤") || reaction.includes("♥️")) return "❤️";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
export function safeForSql(text: string): boolean {
|
||||
return !/[\0\x08\x09\x1a\n\r"'\\\%]/g.test(text);
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import { nativeRandomStr } from "native-utils/built/index.js";
|
||||
|
||||
export function secureRndstr(length = 32, _ = true): string {
|
||||
return nativeRandomStr(length);
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export function sqlLikeEscape(s: string) {
|
||||
return s.replace(/([%_])/g, "\\$1");
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { db } from "@/db/postgre.js";
|
||||
import { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import { awaitAll } from "@/prelude/await-all.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import config from "@/config/index.js";
|
||||
|
|
|
@ -5,7 +5,7 @@ import config from "@/config/index.js";
|
|||
import type { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import type { IActivity } from "@/remote/activitypub/type.js";
|
||||
import type { Webhook, webhookEventTypes } from "@/models/entities/webhook.js";
|
||||
import { envOption } from "../env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
|
||||
import processDeliver from "./processors/deliver.js";
|
||||
import processInbox from "./processors/inbox.js";
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as fs from "node:fs";
|
|||
import { queueLogger } from "../../logger.js";
|
||||
import { addFile } from "@/services/drive/add-file.js";
|
||||
import { format as dateFormat } from "date-fns";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import { getFullApAccount } from "native-utils/built/index.js";
|
||||
import { createTemp } from "@/misc/create-temp.js";
|
||||
import { Users, Blockings } from "@/models/index.js";
|
||||
import { MoreThan } from "typeorm";
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as fs from "node:fs";
|
|||
import { queueLogger } from "../../logger.js";
|
||||
import { addFile } from "@/services/drive/add-file.js";
|
||||
import { format as dateFormat } from "date-fns";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import { getFullApAccount } from "native-utils/built/index.js";
|
||||
import { createTemp } from "@/misc/create-temp.js";
|
||||
import { Users, Followings, Mutings } from "@/models/index.js";
|
||||
import { In, MoreThan, Not } from "typeorm";
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as fs from "node:fs";
|
|||
import { queueLogger } from "../../logger.js";
|
||||
import { addFile } from "@/services/drive/add-file.js";
|
||||
import { format as dateFormat } from "date-fns";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import { getFullApAccount } from "native-utils/built/index.js";
|
||||
import { createTemp } from "@/misc/create-temp.js";
|
||||
import { Users, Mutings } from "@/models/index.js";
|
||||
import { IsNull, MoreThan } from "typeorm";
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as fs from "node:fs";
|
|||
import { queueLogger } from "../../logger.js";
|
||||
import { addFile } from "@/services/drive/add-file.js";
|
||||
import { format as dateFormat } from "date-fns";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import { getFullApAccount } from "native-utils/built/index.js";
|
||||
import { createTemp } from "@/misc/create-temp.js";
|
||||
import { Users, UserLists, UserListJoinings } from "@/models/index.js";
|
||||
import { In } from "typeorm";
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { stringToAcct } from "native-utils/built/index.js";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { isSelfHost, stringToAcct, toPuny } from "native-utils/built/index.js";
|
||||
import { Users, DriveFiles } from "@/models/index.js";
|
||||
import type { DbUserImportJobData } from "@/queue/types.js";
|
||||
import block from "@/services/blocking/create.js";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import * as Post from "@/misc/post.js";
|
||||
import { convertToHiddenPost } from "native-utils/built/index.js";
|
||||
import create from "@/services/note/create.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import type { DbUserImportMastoPostJobData } from "@/queue/types.js";
|
||||
|
@ -52,7 +52,8 @@ export async function importCkPost(
|
|||
logger.error(`Skipped adding file to drive: ${url}`);
|
||||
}
|
||||
}
|
||||
const { text, cw, localOnly, createdAt, visibility } = Post.parse(post);
|
||||
const { text, cw, localOnly, createdAt, visibility } =
|
||||
convertToHiddenPost(post);
|
||||
let note = await Notes.findOneBy({
|
||||
createdAt: createdAt,
|
||||
text: text,
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { IsNull } from "typeorm";
|
||||
import follow from "@/services/following/create.js";
|
||||
|
||||
import { stringToAcct } from "native-utils/built/index.js";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { isSelfHost, stringToAcct, toPuny } from "native-utils/built/index.js";
|
||||
import { Users, DriveFiles } from "@/models/index.js";
|
||||
import type { DbUserImportJobData } from "@/queue/types.js";
|
||||
import { queueLogger } from "../../logger.js";
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { stringToAcct } from "native-utils/built/index.js";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { isSelfHost, stringToAcct, toPuny } from "native-utils/built/index.js";
|
||||
import { Users, DriveFiles, Mutings } from "@/models/index.js";
|
||||
import type { DbUserImportJobData } from "@/queue/types.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import type Bull from "bull";
|
||||
|
||||
import { queueLogger } from "../../logger.js";
|
||||
import { stringToAcct } from "native-utils/built/index.js";
|
||||
import { resolveUser } from "@/remote/resolve-user.js";
|
||||
import { pushUserToUserList } from "@/services/user-list/push.js";
|
||||
import { downloadTextFile } from "@/misc/download-text-file.js";
|
||||
import { isSelfHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { isSelfHost, stringToAcct, toPuny } from "native-utils/built/index.js";
|
||||
import {
|
||||
DriveFiles,
|
||||
Users,
|
||||
|
|
|
@ -4,7 +4,7 @@ import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instanc
|
|||
import Logger from "@/services/logger.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import { StatusError } from "@/misc/fetch.js";
|
||||
import { shouldSkipInstance } from "@/misc/skipped-instances.js";
|
||||
import type { DeliverJobData } from "@/queue/types.js";
|
||||
|
|
|
@ -6,7 +6,7 @@ import Logger from "@/services/logger.js";
|
|||
import { registerOrFetchInstanceDoc } from "@/services/register-or-fetch-instance-doc.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { toPuny, extractDbHost } from "@/misc/convert-host.js";
|
||||
import { toPuny, extractHost } from "native-utils/built/index.js";
|
||||
import { getApId } from "@/remote/activitypub/type.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
import type { InboxJobData } from "../types.js";
|
||||
|
@ -158,7 +158,7 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
}
|
||||
|
||||
// ブロックしてたら中断
|
||||
const ldHost = extractDbHost(authUser.user.uri);
|
||||
const ldHost = extractHost(authUser.user.uri);
|
||||
if (await shouldBlockInstance(ldHost, meta)) {
|
||||
return `Blocked request: ${ldHost}`;
|
||||
}
|
||||
|
@ -169,8 +169,8 @@ export default async (job: Bull.Job<InboxJobData>): Promise<string> => {
|
|||
|
||||
// activity.idがあればホストが署名者のホストであることを確認する
|
||||
if (typeof activity.id === "string") {
|
||||
const signerHost = extractDbHost(authUser.user.uri!);
|
||||
const activityIdHost = extractDbHost(activity.id);
|
||||
const signerHost = extractHost(authUser.user.uri!);
|
||||
const activityIdHost = extractHost(activity.id);
|
||||
if (signerHost !== activityIdHost) {
|
||||
return `skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { URL } from "url";
|
|||
import httpSignature, { IParsedSignature } from "@peertube/http-signature";
|
||||
import config from "@/config/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import DbResolver from "@/remote/activitypub/db-resolver.js";
|
||||
import { getApId } from "@/remote/activitypub/type.js";
|
||||
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
||||
|
|
|
@ -5,7 +5,7 @@ import type { IAnnounce } from "../../type.js";
|
|||
import { getApId } from "../../type.js";
|
||||
import { fetchNote, resolveNote } from "../../models/note.js";
|
||||
import { apLogger } from "../../logger.js";
|
||||
import { extractDbHost } from "@/misc/convert-host.js";
|
||||
import { extractHost } from "native-utils/built/index.js";
|
||||
import { getApLock } from "@/misc/app-lock.js";
|
||||
import { parseAudience } from "../../audience.js";
|
||||
import { StatusError } from "@/misc/fetch.js";
|
||||
|
@ -30,7 +30,7 @@ export default async function (
|
|||
}
|
||||
|
||||
// Interrupt if you block the announcement destination
|
||||
if (await shouldBlockInstance(extractDbHost(uri))) return;
|
||||
if (await shouldBlockInstance(extractHost(uri))) return;
|
||||
|
||||
const lock = await getApLock(uri);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { createNote, fetchNote } from "../../models/note.js";
|
|||
import type { IObject, ICreate } from "../../type.js";
|
||||
import { getApId } from "../../type.js";
|
||||
import { getApLock } from "@/misc/app-lock.js";
|
||||
import { extractDbHost } from "@/misc/convert-host.js";
|
||||
import { extractHost } from "native-utils/built/index.js";
|
||||
import { StatusError } from "@/misc/fetch.js";
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ export default async function (
|
|||
}
|
||||
|
||||
if (typeof note.id === "string") {
|
||||
if (extractDbHost(actor.uri) !== extractDbHost(note.id)) {
|
||||
if (extractHost(actor.uri) !== extractHost(note.id)) {
|
||||
return "skip: host in actor.uri !== note.id";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ import block from "./block/index.js";
|
|||
import flag from "./flag/index.js";
|
||||
import move from "./move/index.js";
|
||||
import type { IObject, IActivity } from "../type.js";
|
||||
import { extractDbHost } from "@/misc/convert-host.js";
|
||||
import { extractHost } from "native-utils/built/index.js";
|
||||
import { shouldBlockInstance } from "@/misc/should-block-instance.js";
|
||||
|
||||
export async function performActivity(
|
||||
|
@ -71,7 +71,7 @@ async function performOneActivity(
|
|||
if (actor.isSuspended) return;
|
||||
|
||||
if (typeof activity.id !== "undefined") {
|
||||
const host = extractDbHost(getApId(activity));
|
||||
const host = extractHost(getApId(activity));
|
||||
if (await shouldBlockInstance(host)) return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { CacheableRemoteUser } from "@/models/entities/user.js";
|
||||
import type { IRead } from "../type.js";
|
||||
import { getApId } from "../type.js";
|
||||
import { isSelfHost, extractDbHost } from "@/misc/convert-host.js";
|
||||
import { isSelfHost, extractHost } from "native-utils/built/index.js";
|
||||
import { MessagingMessages } from "@/models/index.js";
|
||||
import { readUserMessagingMessage } from "@/server/api/common/read-messaging-message.js";
|
||||
|
||||
|
@ -11,7 +11,7 @@ export const performReadActivity = async (
|
|||
): Promise<string> => {
|
||||
const id = await getApId(activity.object);
|
||||
|
||||
if (!isSelfHost(extractDbHost(id))) {
|
||||
if (!isSelfHost(extractHost(id))) {
|
||||
return `skip: Read to foreign host (${id})`;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { extractPollFromQuestion } from "./question.js";
|
|||
import vote from "@/services/note/polls/vote.js";
|
||||
import { apLogger } from "../logger.js";
|
||||
import { DriveFile } from "@/models/entities/drive-file.js";
|
||||
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
|
||||
import { extractHost, toPuny } from "native-utils/built/index.js";
|
||||
import {
|
||||
Emojis,
|
||||
Polls,
|
||||
|
@ -54,7 +54,7 @@ import { langmap } from "@/misc/langmap.js";
|
|||
const logger = apLogger;
|
||||
|
||||
export function validateNote(object: any, uri: string) {
|
||||
const expectHost = extractDbHost(uri);
|
||||
const expectHost = extractHost(uri);
|
||||
|
||||
if (object == null) {
|
||||
return new Error("invalid Note: object is null");
|
||||
|
@ -64,9 +64,9 @@ export function validateNote(object: any, uri: string) {
|
|||
return new Error(`invalid Note: invalid object type ${getApType(object)}`);
|
||||
}
|
||||
|
||||
if (object.id && extractDbHost(object.id) !== expectHost) {
|
||||
if (object.id && extractHost(object.id) !== expectHost) {
|
||||
return new Error(
|
||||
`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractDbHost(
|
||||
`invalid Note: id has different host. expected: ${expectHost}, actual: ${extractHost(
|
||||
object.id,
|
||||
)}`,
|
||||
);
|
||||
|
@ -74,10 +74,10 @@ export function validateNote(object: any, uri: string) {
|
|||
|
||||
if (
|
||||
object.attributedTo &&
|
||||
extractDbHost(getOneApId(object.attributedTo)) !== expectHost
|
||||
extractHost(getOneApId(object.attributedTo)) !== expectHost
|
||||
) {
|
||||
return new Error(
|
||||
`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractDbHost(
|
||||
`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${extractHost(
|
||||
object.attributedTo,
|
||||
)}`,
|
||||
);
|
||||
|
@ -422,11 +422,11 @@ export async function resolveNote(
|
|||
if (uri == null) throw new Error("missing uri");
|
||||
|
||||
// Abort if origin host is blocked
|
||||
if (await shouldBlockInstance(extractDbHost(uri)))
|
||||
if (await shouldBlockInstance(extractHost(uri)))
|
||||
throw new StatusError(
|
||||
"host blocked",
|
||||
451,
|
||||
`host ${extractDbHost(uri)} is blocked`,
|
||||
`host ${extractHost(uri)} is blocked`,
|
||||
);
|
||||
|
||||
const lock = await getApLock(uri);
|
||||
|
|
|
@ -19,7 +19,7 @@ import { UserNotePining } from "@/models/entities/user-note-pining.js";
|
|||
import { genId } from "@/misc/gen-id.js";
|
||||
import { UserPublickey } from "@/models/entities/user-publickey.js";
|
||||
import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { toArray } from "@/prelude/array.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
|
|
|
@ -3,7 +3,7 @@ import { getJson } from "@/misc/fetch.js";
|
|||
import type { ILocalUser } from "@/models/entities/user.js";
|
||||
import { getInstanceActor } from "@/services/instance-actor.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { extractDbHost, isSelfHost } from "@/misc/convert-host.js";
|
||||
import { extractHost, isSelfHost } from "native-utils/built/index.js";
|
||||
import { signedGet } from "./request.js";
|
||||
import type { IObject, ICollection, IOrderedCollection } from "./type.js";
|
||||
import { isCollectionOrOrderedCollection, getApId } from "./type.js";
|
||||
|
@ -62,7 +62,7 @@ export default class Resolver {
|
|||
if (typeof value !== "string") {
|
||||
apLogger.debug("Object to resolve is not a string");
|
||||
if (typeof value.id !== "undefined") {
|
||||
const host = extractDbHost(getApId(value));
|
||||
const host = extractHost(getApId(value));
|
||||
if (await shouldBlockInstance(host)) {
|
||||
throw new Error("instance is blocked");
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export default class Resolver {
|
|||
}
|
||||
this.history.add(value);
|
||||
|
||||
const host = extractDbHost(value);
|
||||
const host = extractHost(value);
|
||||
if (isSelfHost(host)) {
|
||||
return await this.resolveLocal(value);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { IsNull } from "typeorm";
|
|||
import config from "@/config/index.js";
|
||||
import type { User, IRemoteUser } from "@/models/entities/user.js";
|
||||
import { Users } from "@/models/index.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import webFinger from "./webfinger.js";
|
||||
import { createPerson, updatePerson } from "./activitypub/models/person.js";
|
||||
import { remoteLogger } from "./logger.js";
|
||||
|
|
|
@ -9,7 +9,7 @@ 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 } from "native-utils/built/index.js";
|
||||
import {
|
||||
Notes,
|
||||
Users,
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
||||
import { genString } from "native-utils/built/index.js";
|
||||
|
||||
export default () => secureRndstr(16, true);
|
||||
export default () => genString(16);
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Users, UsedUsernames } from "@/models/index.js";
|
|||
import { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { IsNull } from "typeorm";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { toPunyNullable } from "@/misc/convert-host.js";
|
||||
import { toPunyOptional } from "native-utils/built/index.js";
|
||||
import { UserKeypair } from "@/models/entities/user-keypair.js";
|
||||
import { UsedUsername } from "@/models/entities/used-username.js";
|
||||
import { db } from "@/db/postgre.js";
|
||||
|
@ -100,7 +100,7 @@ export async function signup(opts: {
|
|||
createdAt: new Date(),
|
||||
username: username,
|
||||
usernameLower: username.toLowerCase(),
|
||||
host: toPunyNullable(host),
|
||||
host: toPunyOptional(host),
|
||||
token: secret,
|
||||
isAdmin:
|
||||
(await Users.countBy({
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { Emojis } from "@/models/index.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape, toPuny } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin", "emoji"],
|
||||
|
|
|
@ -2,7 +2,7 @@ import define from "@/server/api/define.js";
|
|||
import { Emojis } from "@/models/index.js";
|
||||
import { makePaginationQuery } from "../../../common/make-pagination-query.js";
|
||||
import type { Emoji } from "@/models/entities/emoji.js";
|
||||
//import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
//import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
import { ApiError } from "../../../error.js";
|
||||
|
||||
export const meta = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js";
|
||||
|
||||
export const meta = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Users } from "@/models/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["admin"],
|
||||
|
|
|
@ -4,7 +4,7 @@ import { createNote } from "@/remote/activitypub/models/note.js";
|
|||
import DbResolver from "@/remote/activitypub/db-resolver.js";
|
||||
import Resolver from "@/remote/activitypub/resolver.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { extractDbHost } from "@/misc/convert-host.js";
|
||||
import { extractHost } from "native-utils/built/index.js";
|
||||
import { Users, Notes } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { CacheableLocalUser, User } from "@/models/entities/user.js";
|
||||
|
@ -101,7 +101,7 @@ async function fetchAny(
|
|||
me: CacheableLocalUser | null | undefined,
|
||||
): Promise<SchemaType<(typeof meta)["res"]> | null> {
|
||||
// Wait if blocked.
|
||||
if (await shouldBlockInstance(extractDbHost(uri))) return null;
|
||||
if (await shouldBlockInstance(extractHost(uri))) return null;
|
||||
|
||||
const dbResolver = new DbResolver();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import define from "@/server/api/define.js";
|
|||
import { Apps } from "@/models/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { unique } from "@/prelude/array.js";
|
||||
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
||||
import { genString } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["app"],
|
||||
|
@ -41,7 +41,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
includeSecret: true,
|
||||
});
|
||||
// Generate secret
|
||||
const secret = secureRndstr(32, true);
|
||||
const secret = genString(32);
|
||||
|
||||
// for backward compatibility
|
||||
const permission = unique(
|
||||
|
|
|
@ -3,7 +3,7 @@ import define from "@/server/api/define.js";
|
|||
import { ApiError } from "@/server/api/error.js";
|
||||
import { AuthSessions, AccessTokens, Apps } from "@/models/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
||||
import { genString } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["auth"],
|
||||
|
@ -38,10 +38,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
}
|
||||
|
||||
// Generate access token
|
||||
const accessToken = secureRndstr(32, true);
|
||||
const accessToken = genString(32);
|
||||
|
||||
// Fetch exist access token
|
||||
const exist = await AccessTokens.exist({
|
||||
const exist = await AccessTokens.exists({
|
||||
where: {
|
||||
appId: session.appId,
|
||||
userId: user.id,
|
||||
|
|
|
@ -2,7 +2,7 @@ import define from "@/server/api/define.js";
|
|||
import { Brackets } from "typeorm";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import { Channels } from "@/models/index.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["channels"],
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["federation"],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["federation"],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { Hashtags } from "@/models/index.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["hashtags"],
|
||||
|
|
|
@ -3,7 +3,7 @@ import define from "@/server/api/define.js";
|
|||
import { fetchMeta } from "@/misc/fetch-meta.js";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import type { Note } from "@/models/entities/note.js";
|
||||
import { safeForSql } from "@/misc/safe-for-sql.js";
|
||||
import { safeForSql } from "native-utils/built/index.js";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import define from "@/server/api/define.js";
|
||||
import { AccessTokens } from "@/models/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { secureRndstr } from "@/misc/secure-rndstr.js";
|
||||
import { genString } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["auth"],
|
||||
|
@ -44,7 +44,7 @@ export const paramDef = {
|
|||
|
||||
export default define(meta, paramDef, async (ps, user) => {
|
||||
// Generate access token
|
||||
const accessToken = secureRndstr(32, true);
|
||||
const accessToken = genString(32);
|
||||
|
||||
const now = new Date();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Brackets } from "typeorm";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { safeForSql } from "@/misc/safe-for-sql.js";
|
||||
import { safeForSql } from "native-utils/built/index.js";
|
||||
import { normalizeForSearch } from "@/misc/normalize-for-search.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
|
|
|
@ -10,7 +10,7 @@ import { makePaginationQuery } from "@/server/api/common/make-pagination-query.j
|
|||
import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js";
|
||||
import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js";
|
||||
import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["notes"],
|
||||
|
|
|
@ -44,9 +44,9 @@ async function translateCommitMsg(msg: string, targetLang: Language) {
|
|||
|
||||
if (targetLang.startsWith("ja")) {
|
||||
const prefixes = {
|
||||
container: "コンテナ (Podman/Docker)",
|
||||
chore: "雑務",
|
||||
dev: "開発",
|
||||
docker: "Docker",
|
||||
docs: "ドキュメント",
|
||||
feat: "新機能",
|
||||
fix: "修正",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IsNull } from "typeorm";
|
||||
import { Users, Followings, UserProfiles } from "@/models/index.js";
|
||||
import { toPunyNullable } from "@/misc/convert-host.js";
|
||||
import { toPunyOptional } from "native-utils/built/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
|
@ -80,7 +80,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
? { id: ps.userId }
|
||||
: {
|
||||
usernameLower: ps.username?.toLowerCase(),
|
||||
host: toPunyNullable(ps.host) ?? IsNull(),
|
||||
host: toPunyOptional(ps.host) ?? IsNull(),
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IsNull } from "typeorm";
|
||||
import { Users, Followings, UserProfiles } from "@/models/index.js";
|
||||
import { toPunyNullable } from "@/misc/convert-host.js";
|
||||
import { toPunyOptional } from "native-utils/built/index.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { ApiError } from "@/server/api/error.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
|
@ -79,7 +79,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
|||
? { id: ps.userId }
|
||||
: {
|
||||
usernameLower: ps.username?.toLowerCase(),
|
||||
host: toPunyNullable(ps.host) ?? IsNull(),
|
||||
host: toPunyOptional(ps.host) ?? IsNull(),
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Brackets } from "typeorm";
|
|||
import { Followings, Users } from "@/models/index.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["users"],
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Brackets } from "typeorm";
|
|||
import { UserProfiles, Users } from "@/models/index.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import define from "@/server/api/define.js";
|
||||
import { sqlLikeEscape } from "@/misc/sql-like-escape.js";
|
||||
import { sqlLikeEscape } from "native-utils/built/index.js";
|
||||
|
||||
export const meta = {
|
||||
tags: ["users"],
|
||||
|
|
|
@ -2,7 +2,7 @@ import Limiter from "ratelimiter";
|
|||
import Logger from "@/services/logger.js";
|
||||
import { redisClient } from "@/db/redis.js";
|
||||
import type { IEndpointMeta } from "./endpoints.js";
|
||||
import { convertMilliseconds } from "@/misc/convert-milliseconds.js";
|
||||
import { formatMilliseconds } from "native-utils/built/index.js";
|
||||
|
||||
const logger = new Logger("limiter");
|
||||
|
||||
|
@ -78,7 +78,7 @@ export const limiter = (
|
|||
if (info.remaining === 0) {
|
||||
reject({
|
||||
message: "RATE_LIMIT_EXCEEDED",
|
||||
remainingTime: convertMilliseconds(info.resetMs - Date.now()),
|
||||
remainingTime: formatMilliseconds(info.resetMs - Date.now()),
|
||||
});
|
||||
} else {
|
||||
ok();
|
||||
|
|
|
@ -20,7 +20,7 @@ import { fetchMeta } from "@/misc/fetch-meta.js";
|
|||
import { genIdenticon } from "@/misc/gen-identicon.js";
|
||||
import { createTemp } from "@/misc/create-temp.js";
|
||||
import { stringToAcct } from "native-utils/built/index.js";
|
||||
import { envOption } from "@/env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
import megalodon, { MegalodonInterface } from "megalodon";
|
||||
import activityPub from "./activitypub.js";
|
||||
import nodeinfo from "./nodeinfo.js";
|
||||
|
|
|
@ -2,7 +2,7 @@ import cluster from "node:cluster";
|
|||
import chalk from "chalk";
|
||||
import { default as convertColor } from "color-convert";
|
||||
import { format as dateFormat } from "date-fns";
|
||||
import { envOption } from "@/env.js";
|
||||
import { envOption } from "@/config/index.js";
|
||||
import config from "@/config/index.js";
|
||||
|
||||
import * as SyslogPro from "syslog-pro";
|
||||
|
|
|
@ -22,7 +22,7 @@ import renderNote from "@/remote/activitypub/renderer/note.js";
|
|||
import renderCreate from "@/remote/activitypub/renderer/create.js";
|
||||
import { renderActivity } from "@/remote/activitypub/renderer/index.js";
|
||||
import { deliver } from "@/queue/index.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
|
||||
export async function createMessage(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { Instance } from "@/models/entities/instance.js";
|
||||
import { Instances } from "@/models/index.js";
|
||||
import { genId } from "@/misc/gen-id.js";
|
||||
import { toPuny } from "@/misc/convert-host.js";
|
||||
import { toPuny } from "native-utils/built/index.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
|
||||
const cache = new Cache<Instance>("registerOrFetchInstanceDoc", 60 * 60);
|
||||
|
|
|
@ -229,13 +229,16 @@ function saveFields() {
|
|||
});
|
||||
}
|
||||
|
||||
const convertEmptyStringToNull = (x) =>
|
||||
x === "" ? null : x == null ? undefined : x;
|
||||
|
||||
function save() {
|
||||
os.apiWithDialog("i/update", {
|
||||
name: profile.name ?? undefined,
|
||||
description: profile.description ?? undefined,
|
||||
location: profile.location ?? undefined,
|
||||
birthday: profile.birthday ?? undefined,
|
||||
lang: profile.lang ?? undefined,
|
||||
name: convertEmptyStringToNull(profile.name),
|
||||
description: convertEmptyStringToNull(profile.description),
|
||||
location: convertEmptyStringToNull(profile.location),
|
||||
birthday: convertEmptyStringToNull(profile.birthday),
|
||||
lang: convertEmptyStringToNull(profile.lang),
|
||||
isBot: !!profile.isBot,
|
||||
isCat: !!profile.isCat,
|
||||
speakAsCat: profile.isCat ? !!profile.speakAsCat : undefined,
|
||||
|
|
|
@ -10,7 +10,7 @@ OLD_COMMIT=$(git rev-parse --short HEAD)
|
|||
|
||||
say 'Pulling changes from the remote repo...'
|
||||
run 'git checkout -- package.json packages/backend/assets'
|
||||
run 'git pull --ff --no-edit --autostash --strategy-option theirs'
|
||||
run 'git pull --ff --no-edit --autostash --strategy-option theirs origin main'
|
||||
|
||||
NEW_COMMIT=$(git rev-parse --short HEAD)
|
||||
|
||||
|
|
Loading…
Reference in a new issue