Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance(backend): refine system account #15530

Open
wants to merge 30 commits into
base: develop
Choose a base branch
from
Open

enhance(backend): refine system account #15530

wants to merge 30 commits into from

Conversation

syuilo
Copy link
Member

@syuilo syuilo commented Feb 21, 2025

What

Fix #15525
Fix #14857

  • 柔軟性確保のため、システムアカウントをユーザー名ハードコードではなく別テーブルで管理するようにした
  • システムアカウントを消せないようにした
  • proxyアカウントのシステムアカウント化
  • isRootなアカウントかどうかをユーザーテーブルのカラムではなくmetaに持つようにしユーザーテーブルの効率化

Why

Additional info (optional)

Checklist

  • Read the contribution guide
  • Test working in a local environment
  • (If needed) Add story of storybook
  • (If needed) Update CHANGELOG.md
  • (If possible) Add tests

@github-actions github-actions bot added the packages/backend Server side specific issue/PR label Feb 21, 2025
Copy link

codecov bot commented Feb 21, 2025

Codecov Report

Attention: Patch coverage is 62.95620% with 203 lines in your changes missing coverage. Please review.

Project coverage is 44.14%. Comparing base (7c87dec) to head (c935e0c).

Files with missing lines Patch % Lines
packages/backend/src/core/SystemAccountService.ts 81.06% 32 Missing ⚠️
packages/frontend/src/pages/admin-user.vue 0.00% 28 Missing ⚠️
.../backend/src/core/activitypub/ApRendererService.ts 33.33% 26 Missing ⚠️
...server/api/endpoints/admin/update-proxy-account.ts 59.67% 25 Missing ⚠️
...kages/backend/src/server/api/endpoints/reset-db.ts 16.66% 15 Missing ⚠️
packages/frontend/src/pages/admin/settings.vue 0.00% 15 Missing ⚠️
packages/backend/src/core/MetaService.ts 7.69% 12 Missing ⚠️
packages/backend/src/core/DeleteAccountService.ts 46.15% 7 Missing ⚠️
packages/backend/src/core/SignupService.ts 44.44% 5 Missing ⚠️
.../src/server/api/endpoints/admin/accounts/create.ts 16.66% 5 Missing ⚠️
... and 12 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #15530      +/-   ##
===========================================
+ Coverage    40.86%   44.14%   +3.28%     
===========================================
  Files         1609     1613       +4     
  Lines       161806   167798    +5992     
  Branches      3786     4141     +355     
===========================================
+ Hits         66119    74082    +7963     
+ Misses       95239    93236    -2003     
- Partials       448      480      +32     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

たった1レコードのために全userレコードにフラグ持たせるの無駄すぎるからisRoot消してmetaに移動させた

@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

proxyアカウントのアイコンをサーバーアイコンにしたいけどサーバーアイコンはdriveFileとして存在していないからめんどいわね

@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

システムドライブ機能を先に実装する必要がある可能性が出てきた

@github-actions github-actions bot added packages/frontend Client side specific issue/PR packages/misskey-js labels Feb 21, 2025
Copy link
Contributor

github-actions bot commented Feb 21, 2025

このPRによるapi.jsonの差分

差分はこちら
--- base
+++ head
@@ -9660,10 +9660,7 @@
                       "type": "boolean"
                     },
                     "proxyAccountId": {
-                      "type": [
-                        "string",
-                        "null"
-                      ],
+                      "type": "string",
                       "format": "id"
                     },
                     "email": {
@@ -17384,13 +17381,6 @@
                   "enableSensitiveMediaDetectionForVideos": {
                     "type": "boolean"
                   },
-                  "proxyAccountId": {
-                    "type": [
-                      "string",
-                      "null"
-                    ],
-                    "format": "misskey:id"
-                  },
                   "maintainerName": {
                     "type": [
                       "string",
@@ -17732,6 +17722,163 @@
           },
           "400": {
             "description": "Client error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                },
+                "examples": {
+                  "INVALID_PARAM": {
+                    "value": {
+                      "error": {
+                        "message": "Invalid param.",
+                        "code": "INVALID_PARAM",
+                        "id": "3d81ceae-475f-4600-b2a8-2bc116157532"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "401": {
+            "description": "Authentication error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                },
+                "examples": {
+                  "CREDENTIAL_REQUIRED": {
+                    "value": {
+                      "error": {
+                        "message": "Credential required.",
+                        "code": "CREDENTIAL_REQUIRED",
+                        "id": "1384574d-a912-4b81-8601-c7b1c4085df1"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "403": {
+            "description": "Forbidden error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                },
+                "examples": {
+                  "AUTHENTICATION_FAILED": {
+                    "value": {
+                      "error": {
+                        "message": "Authentication failed. Please ensure your token is correct.",
+                        "code": "AUTHENTICATION_FAILED",
+                        "id": "b0a7f5f8-dc2f-4171-b91f-de88ad238e14"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "418": {
+            "description": "I'm Ai",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                },
+                "examples": {
+                  "I_AM_AI": {
+                    "value": {
+                      "error": {
+                        "message": "You sent a request to Ai-chan, Misskey's showgirl, instead of the server.",
+                        "code": "I_AM_AI",
+                        "id": "60c46cd1-f23a-46b1-bebe-5d2b73951a84"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "500": {
+            "description": "Internal server error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                },
+                "examples": {
+                  "INTERNAL_ERROR": {
+                    "value": {
+                      "error": {
+                        "message": "Internal error occurred. Please contact us if the error persists.",
+                        "code": "INTERNAL_ERROR",
+                        "id": "5d37dbcb-891e-41ca-a3d6-e690c97775ac"
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/admin/update-proxy-account": {
+      "post": {
+        "operationId": "post___admin___update-proxy-account",
+        "summary": "admin/update-proxy-account",
+        "description": "No description provided.\n\n**Credential required**: *Yes* / **Permission**: *write:admin:account*",
+        "externalDocs": {
+          "description": "Source code",
+          "url": "https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/api/endpoints/admin/update-proxy-account.ts"
+        },
+        "tags": [
+          "admin"
+        ],
+        "security": [
+          {
+            "bearerAuth": []
+          }
+        ],
+        "requestBody": {
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "type": "object",
+                "properties": {
+                  "description": {
+                    "type": [
+                      "string",
+                      "null"
+                    ],
+                    "minLength": 1,
+                    "maxLength": 1500
+                  }
+                }
+              }
+            }
+          }
+        },
+        "responses": {
+          "200": {
+            "description": "OK (with results)",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "object",
+                  "$ref": "#/components/schemas/UserDetailed"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "Client error",
             "content": {
               "application/json": {
                 "schema": {

Get diff files from Workflow Page

@samunohito
Copy link
Member

オッ

@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

ほぼ完成

@syuilo syuilo marked this pull request as ready for review February 21, 2025 12:07
@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

proxyアカウントのアイコンをサーバーアイコンにしたいけどサーバーアイコンはdriveFileとして存在していないからめんどいわね

これどうするかなぁ

@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

urlだけ設定するのでもいいけどurlが設定されているのにavatarIdがnullになっていると不具合起きそう

@syuilo
Copy link
Member Author

syuilo commented Feb 21, 2025

Userをpackするときに上書きしてもいいけどいちいちプロキシかどうかチェックするのもな

@Sayamame-beans
Copy link
Member

ファイル用のシステムアカウントを用意しても良いのかも? みたいな話はおさむさんがされてましたね…(しかし、本人とファイルの所有者が異なるとマズい? 良い感じに共用するみたいなことをしないといけない…?)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

(ちなみにそのような実装になっているのは昔から)

Comment on lines +15 to +16
await queryRunner.query(`ALTER TABLE "meta" ADD "proxyAccountId" character varying(32)`);
await queryRunner.query(`ALTER TABLE "meta" ADD CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad" FOREIGN KEY ("proxyAccountId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

system_accountテーブルからmeta.proxyAccountIdを復元するクエリがあったほうが良いように思えます。

@samunohito
Copy link
Member

テストpassしました

@samunohito
Copy link
Member

ちなみに、

  • UserEntityServiceは既にmetaを引き込んでいる
  • pack()の途中で呼ばれるgetIdenticonUrl()で既に使われている
  • UserLiteの範囲で判定条件がそろう

なので、isSystemフラグを持たせるのにあたりパフォーマンスへの心配は無いと思います。

@tai-cha
Copy link
Contributor

tai-cha commented Feb 23, 2025

isSystemをuserLiteとかuserDetailedに載せずにフロントエンドで.の有無で判断してる理由ってなんでかしら?パフォーマンスへの懸念です?(そこにデータを載せれば.をシステムアカウント名に含むという縛りはなくすことも可能そうだと思い)

とりあえずパフォーマンスへの影響を無くす実装を選びました

これひと晩置いてよく考えたら昔から使われているプロキシアカウントもシステム化するのだから(つまり必ず.が入るわけではないので)結局この判定ではプロキシアカウントがすり抜けてしまうのでは…?

@tai-cha
Copy link
Contributor

tai-cha commented Feb 23, 2025

あとひとりサーバー等で自身をプロキシアカウントにしている例やサーバー公式アカウントをプロキシアカウントにしている例などがあるためリリースノートにはNOTEの記載が必須そう(アカウントの扱いが変わると思われるため)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

ちなみに、

  • UserEntityServiceは既にmetaを引き込んでいる
  • pack()の途中で呼ばれるgetIdenticonUrl()で既に使われている
  • UserLiteの範囲で判定条件がそろう

なので、isSystemフラグを持たせるのにあたりパフォーマンスへの心配は無いと思います。

isSystemフラグの実装には現在あるシステムアカウントを全て取得する処理が必要になると思ってたけど、.が含まれているかどうかという簡易的な方法で良いのであればパフォーマンスは気にしないで良いわね

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

テストpassしました

🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻🙏🏻

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

isSystemをuserLiteとかuserDetailedに載せずにフロントエンドで.の有無で判断してる理由ってなんでかしら?パフォーマンスへの懸念です?(そこにデータを載せれば.をシステムアカウント名に含むという縛りはなくすことも可能そうだと思い)

とりあえずパフォーマンスへの影響を無くす実装を選びました

これひと晩置いてよく考えたら昔から使われているプロキシアカウントもシステム化するのだから(つまり必ず.が入るわけではないので)結局この判定ではプロキシアカウントがすり抜けてしまうのでは…?

ので、システムアカウントかどうかが重要な判定では . 判定は使わずにちゃんとした判定を行っています(DeleteAccountServiceのとこ等)

@tai-cha
Copy link
Contributor

tai-cha commented Feb 23, 2025

どうせなら #14854 もケアできる形にしたいのと、システムアカウント判定をクリーンに同じ方法で書けるのが好ましいと考えています
方法としてはデータ量も変更回数も多くないため、redisなどにシステムユーザーのuserIdと種別を持たせてもあまりパフォーマンスに問題ない気がしています
そのうえでredisキャッシュを利用してisSystemなどを取れたらいいと思っています

もちろんmetaからプロキシかどうかをフロントエンドが引っ張れるようにしてもいいけれど、利便性も高いと思い

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

統一するなら . に寄せたいため、現行の通常アカウントのプロキシアカウントは削除もしくは非推奨にして、.付きの完全システムアカウントに移行するとか

@tai-cha
Copy link
Contributor

tai-cha commented Feb 23, 2025

現状のプロキシアカウントを削除か非推奨にするにはフォローの移行ができなくてかなり困る(システムアカウントはログインできなくするのであればフォローインポートもできないはずなので)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

フォロー移行する処理かなんかをかけばよさそう

@Sayamame-beans
Copy link
Member

あとひとりサーバー等で自身をプロキシアカウントにしている例やサーバー公式アカウントをプロキシアカウントにしている例などがあるためリリースノートにはNOTEの記載が必須そう(アカウントの扱いが変わると思われるため)

これを加味すると、現状のプロキシアカウントを削除するのは避けないとまずそうかもですね…(フォロー以外の要素(ノート等諸々)が消えてしまう恐れ)
非推奨だと…システムアカウントという扱いが残るので、自身のアカウントとしてログインしている場合はログイン不可になって詰みそうでしょうか。

@tai-cha
Copy link
Contributor

tai-cha commented Feb 23, 2025

フォロー移行する処理かなんかをかけばよさそう

リモートユーザーが絡むのでDBのマイグレだけでは済まないし、利用者の多いサーバーのプロキシアカウントが飛ばすフォローがえらい数になりそうだと思うのでそれは提案しなかったです(あまり賛成ではない)

また、リモート含めたすべてのフォローが再承認される保証はなく、完全に情報を引き継ぐことが難しい

@samunohito
Copy link
Member

samunohito commented Feb 23, 2025

統一するなら . に寄せたい

たぶん、UserEntityServiceの中でisSystemを作るためにSystemAccountServiceのキャッシュからawaitで中身を取り寄せる処理を入れたくない、ということですよね…?(頭回ってないので違うこと言ってたらごめんなさい)

awaitを1回減らす為だけに完全な判定条件ではない「usernameにドットを含むか否か」を入れ込むのはちょっと尚早かと思いました。今後のことを考えると、あまりとりたく無いアプローチです(強烈な性能劣化を引き起こす等特殊な条件があれば別ですが、それは今回のケースには当たらないと思っている)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

今までのプロキシアカウントをシステムアカウントに変更するというのをやめる(互換性のためSystemAccounテーブルには登録する)のがまるいかもしれない

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

(もともとこのPRも「プロキシアカウントを消すことができないようにする」というのは主目的ではないし)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

たぶん、UserEntityServiceの中でisSystemを作るためにSystemAccountServiceのキャッシュからawaitで中身を取り寄せる処理を入れたくない、ということですよね…?

yes

超高確率でfalseを返すPromiseを逐一生成したくないという感じ(実際にパフォーマンス云々よりも心理的な抵抗の方が強い)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

isSystemの結果を使い回す処理を入れない限り少なくとも二回はPromise生成されそう(isSystemとidenticon)

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

他の箇所でもそういう判定が行われる可能性があることを考えると同期的に判定する処理が良いわね

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

今までのプロキシアカウントをシステムアカウントに変更するというのをやめる(互換性のためSystemAccounテーブルには登録する)のがまるいかもしれない

今まで普通のアカウントだったのが急に操作不能なシステムアカウントになるのは混乱を招く可能性もなくはないというのもある

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

この改修は緊急度が高いため既存プロキシアカウントのシステムアカウント化とシステムアカウント判定方法のリファクタについては後から検討・対応で良いと思われる

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

(どちらも今対応を決めないと取り返しがつかないというわけではない)

@samunohito
Copy link
Member

既存プロキシアカウントのシステムアカウント化とシステムアカウント判定方法

まあ、それはそう…
プロキシアカウント周りは既存実装へとロールバックが必要ですね。

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

ロールバックというよりは今の実装もdeleteAccountを除いて今までのプロキシアカウントがシステムアカウントとして扱われないようになっているからdeleteAccountの判定を.判定に変えるだけになりそう?

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

システムアカウントとして扱われないというか、ユーザーから見た挙動的にシステムアカウントではない

@syuilo
Copy link
Member Author

syuilo commented Feb 23, 2025

ご意見募集中

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment