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

[wip] feat(frontend): Botプロテクションの設定変更時は実際に検証を通過しないと保存できないようにする #15151

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from

Conversation

samunohito
Copy link
Member

@samunohito samunohito commented Dec 19, 2024

What

コントロールパネル→セキュリティのページでBotプロテクションの設定項目を更新する際、実際にcaptchaによる検証を通過しないと設定の更新が行えないようにします。

Why

fix #15137
※セキュリティ的な物というより、実際に動作する環境であるか確認の取れた状態で確定するための意味合いが強いです

Additional info (optional)

実際に各captchaで動作確認(※確認中)

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/frontend Client side specific issue/PR label Dec 19, 2024
@samunohito
Copy link
Member Author

(動確して不備がある or 何らかのレビューコメントが来る…でもない限り、コードを変えることはおそらくないと思います)

@samunohito samunohito added this to the v2024.12.0 milestone Dec 19, 2024
Copy link

codecov bot commented Dec 19, 2024

Codecov Report

Attention: Patch coverage is 66.85962% with 229 lines in your changes missing coverage. Please review.

Project coverage is 41.68%. Comparing base (0804092) to head (7fcf8af).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
...ckages/frontend/src/pages/admin/bot-protection.vue 0.00% 133 Missing ⚠️
...end/src/server/api/endpoints/admin/captcha/save.ts 65.11% 45 Missing ⚠️
packages/frontend/src/components/MkCaptcha.vue 0.00% 35 Missing ⚠️
.../src/server/api/endpoints/admin/captcha/current.ts 88.57% 8 Missing ⚠️
packages/backend/src/core/CaptchaService.ts 97.88% 6 Missing ⚠️
packages/frontend/src/components/MkFormFooter.vue 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #15151      +/-   ##
===========================================
+ Coverage    39.95%   41.68%   +1.73%     
===========================================
  Files         1563     1569       +6     
  Lines       197780   204275    +6495     
  Branches      3633     3743     +110     
===========================================
+ Hits         79029    85159    +6130     
- Misses      118178   118541     +363     
- Partials       573      575       +2     

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

<div>サイトキーに"10000000-ffff-ffff-ffff-000000000001"と入力することで動作をテスト出来ます。<br/>本番運用時には必ず正規のサイトキーを設定してください。</div>
<div>ref: <a href="https://docs.hcaptcha.com/#integration-testing-test-keys" target="_blank">hCaptcha Developer Guide</a></div>
</div>
</MkInfo>
</template>
Copy link
Member Author

Choose a reason for hiding this comment

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

テスト用のサイトキーがデフォルトで入るようになっていたのをやめました。
実物のuiが表示されてしまい、正常に動作していると誤認しかねないと考えたため…

<template v-else-if="botProtectionForm.state.provider === 'testcaptcha'">
<MkInfo warn><span v-html="i18n.ts.testCaptchaWarning"></span></MkInfo>
<FormSlot>
<template #label>{{ i18n.ts.preview }}</template>
<MkCaptcha provider="testcaptcha"/>
<MkCaptcha v-model="testCaptchaResponse" provider="testcaptcha" :sitekey="null"/>
Copy link
Member Author

Choose a reason for hiding this comment

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

型エラーが出てたので

@@ -18,7 +18,7 @@
http-equiv="Content-Security-Policy"
content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/;
worker-src 'self';
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh;
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://*.recaptcha.net https://*.gstatic.com https://challenges.cloudflare.com https://esm.sh;
Copy link
Member Author

Choose a reason for hiding this comment

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

dev modeでreCAPTCHAが表示できなかったので

});
} else {
captchaEl.value.innerHTML = '';
}
Copy link
Member Author

Choose a reason for hiding this comment

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

このあたりの修正は、リロードするまで更新された値でのcaptchaが出来なかったので追加しました

@kakkokari-gtyih
Copy link
Contributor

kakkokari-gtyih commented Dec 19, 2024

実際に値を渡してサーバーサイドの検証まで通るのを確認する(Captcha保存用のAPIをadmin/update-metaから分離してCAPTCHAのリザルトも一緒に送信させるAPIを別途用意する)のを想定してたけどこれでも十分そうかしら

@Ruruke
Copy link

Ruruke commented Dec 19, 2024

自分の方で確認したところSitekeyを1文字でも残してコピーペーストするとPreviewがすごく増えますね。

確認に使用したブランチ

image

@samunohito
Copy link
Member Author

i18nもやらないと…

Copy link
Contributor

github-actions bot commented Dec 20, 2024

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

差分はこちら
--- base
+++ head
@@ -4748,6 +4748,492 @@
         }
       }
     },
+    "/admin/captcha/current": {
+      "post": {
+        "operationId": "admin___captcha___current",
+        "summary": "admin/captcha/current",
+        "description": "No description provided.\n\n**Credential required**: *Yes* / **Permission**: *read:admin:meta*",
+        "externalDocs": {
+          "description": "Source code",
+          "url": "https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/api/endpoints/admin/captcha/current.ts"
+        },
+        "tags": [
+          "admin"
+        ],
+        "security": [
+          {
+            "bearerAuth": []
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "OK (with results)",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "object",
+                  "properties": {
+                    "provider": {
+                      "type": "string",
+                      "enum": [
+                        "none",
+                        "hcaptcha",
+                        "mcaptcha",
+                        "recaptcha",
+                        "turnstile",
+                        "testcaptcha"
+                      ]
+                    },
+                    "hcaptcha": {
+                      "type": "object",
+                      "properties": {
+                        "siteKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        },
+                        "secretKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        }
+                      },
+                      "required": [
+                        "siteKey",
+                        "secretKey"
+                      ]
+                    },
+                    "mcaptcha": {
+                      "type": "object",
+                      "properties": {
+                        "siteKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        },
+                        "secretKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        },
+                        "instanceUrl": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        }
+                      },
+                      "required": [
+                        "siteKey",
+                        "secretKey",
+                        "instanceUrl"
+                      ]
+                    },
+                    "recaptcha": {
+                      "type": "object",
+                      "properties": {
+                        "siteKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        },
+                        "secretKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        }
+                      },
+                      "required": [
+                        "siteKey",
+                        "secretKey"
+                      ]
+                    },
+                    "turnstile": {
+                      "type": "object",
+                      "properties": {
+                        "siteKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        },
+                        "secretKey": {
+                          "type": [
+                            "string",
+                            "null"
+                          ]
+                        }
+                      },
+                      "required": [
+                        "siteKey",
+                        "secretKey"
+                      ]
+                    }
+                  },
+                  "required": [
+                    "provider",
+                    "hcaptcha",
+                    "mcaptcha",
+                    "recaptcha",
+                    "turnstile"
+                  ]
+                }
+              }
+            }
+          },
+          "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/captcha/save": {
+      "post": {
+        "operationId": "admin___captcha___save",
+        "summary": "admin/captcha/save",
+        "description": "No description provided.\n\n**Credential required**: *Yes* / **Permission**: *write:admin:meta*",
+        "externalDocs": {
+          "description": "Source code",
+          "url": "https://github.com/misskey-dev/misskey/blob/develop/packages/backend/src/server/api/endpoints/admin/captcha/save.ts"
+        },
+        "tags": [
+          "admin"
+        ],
+        "security": [
+          {
+            "bearerAuth": []
+          }
+        ],
+        "requestBody": {
+          "required": true,
+          "content": {
+            "application/json": {
+              "schema": {
+                "type": "object",
+                "properties": {
+                  "provider": {
+                    "type": "string",
+                    "enum": [
+                      "none",
+                      "hcaptcha",
+                      "mcaptcha",
+                      "recaptcha",
+                      "turnstile",
+                      "testcaptcha"
+                    ]
+                  },
+                  "captchaResult": {
+                    "type": [
+                      "string",
+                      "null"
+                    ]
+                  },
+                  "sitekey": {
+                    "type": [
+                      "string",
+                      "null"
+                    ]
+                  },
+                  "secret": {
+                    "type": [
+                      "string",
+                      "null"
+                    ]
+                  },
+                  "instanceUrl": {
+                    "type": [
+                      "string",
+                      "null"
+                    ]
+                  }
+                },
+                "required": [
+                  "provider"
+                ]
+              }
+            }
+          }
+        },
+        "responses": {
+          "204": {
+            "description": "OK (without any results)"
+          },
+          "400": {
+            "description": "Client error",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Error"
+                },
+                "examples": {
+                  "INVALID_PROVIDER": {
+                    "value": {
+                      "error": {
+                        "message": "Invalid provider.",
+                        "code": "INVALID_PROVIDER",
+                        "id": "14BF7AE1-80CC-4363-ACB2-4FD61D086AF0",
+                        "httpStatusCode": 400
+                      }
+                    }
+                  },
+                  "INVALID_PARAMETERS": {
+                    "value": {
+                      "error": {
+                        "message": "Invalid parameters.",
+                        "code": "INVALID_PARAMETERS",
+                        "id": "26654194-410E-44E2-B42E-460FF6F92476",
+                        "httpStatusCode": 400
+                      }
+                    }
+                  },
+                  "NO_RESPONSE_PROVIDED": {
+                    "value": {
+                      "error": {
+                        "message": "No response provided.",
+                        "code": "NO_RESPONSE_PROVIDED",
+                        "id": "40ACBBA8-0937-41FB-BB3F-474514D40AFE",
+                        "httpStatusCode": 400
+                      }
+                    }
+                  },
+                  "REQUEST_FAILED": {
+                    "value": {
+                      "error": {
+                        "message": "Request failed.",
+                        "code": "REQUEST_FAILED",
+                        "id": "0F4FE2F1-2C15-4D6E-B714-EFBFCDE231CD",
+                        "httpStatusCode": 500
+                      }
+                    }
+                  },
+                  "VERIFICATION_FAILED": {
+                    "value": {
+                      "error": {
+                        "message": "Verification failed.",
+                        "code": "VERIFICATION_FAILED",
+                        "id": "C41C067F-24F3-4150-84B2-B5A3AE8C2214",
+                        "httpStatusCode": 400
+                      }
+                    }
+                  },
+                  "UNKNOWN": {
+                    "value": {
+                      "error": {
+                        "message": "unknown",
+                        "code": "UNKNOWN",
+                        "id": "F868D509-E257-42A9-99C1-42614B031A97",
+                        "httpStatusCode": 500
+                      }
+                    }
+                  },
+                  "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/delete-all-files-of-a-user": {
       "post": {
         "operationId": "admin___delete-all-files-of-a-user",

Get diff files from Workflow Page

Copy link
Contributor

Choose a reason for hiding this comment

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

errorsのUUIDは全部小文字だったと思う

Comment on lines 223 to 232
await os.apiWithDialog(
'admin/captcha/save',
{
provider: provider as Misskey.entities.AdminCaptchaSaveRequest['provider'],
sitekey: sitekey,
secret: secret,
instanceUrl: botProtectionForm.state.mcaptchaInstanceUrl,
captchaResult: captchaResult.value,
},
);
Copy link
Contributor

@kakkokari-gtyih kakkokari-gtyih Dec 20, 2024

Choose a reason for hiding this comment

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

Suggested change
await os.apiWithDialog(
'admin/captcha/save',
{
provider: provider as Misskey.entities.AdminCaptchaSaveRequest['provider'],
sitekey: sitekey,
secret: secret,
instanceUrl: botProtectionForm.state.mcaptchaInstanceUrl,
captchaResult: captchaResult.value,
},
);
await os.apiWithDialog('admin/captcha/save', {
provider: provider as Misskey.entities.AdminCaptchaSaveRequest['provider'],
sitekey: sitekey,
secret: secret,
instanceUrl: botProtectionForm.state.mcaptchaInstanceUrl,
captchaResult: captchaResult.value,
}, undefined, {
'14bf7ae1-80cc-4363-acb2-4fd61d086af0': {
title: 'このCAPTCHAシステムには対応していません',
text: '設定をお確かめください',
},
// 続き...
});

的なことをやるとエラーハンドリングができる(L230-L233)

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

Successfully merging this pull request may close these issues.

Captchaの設定に不備があるとログインが行えなくなる
3 participants