feat(oauth2): add email format transformation support (#818)

* feat(oauth2): add email format transformation support

- Add enableEmailFormat, userEmailFormat, userEmailReplace fields
- Support regex pattern matching and replacement template ($1, $2, etc.)
- Add Linux Do OAuth2 template with email format pre-configured
- Add input length limit (256 chars) to prevent ReDoS attacks
- Update admin UI with conditional display and tooltips
- Update documentation (zh/en) with configuration examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: update lock files and version

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: restore accessTokenFormat as optional field

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Dream Hunter
2026-01-23 21:30:44 +08:00
committed by GitHub
parent e4c96c9868
commit decede7ed3
13 changed files with 906 additions and 791 deletions

View File

@@ -155,6 +155,9 @@ export type UserOauth2Settings = {
redirectURL: string;
logoutURL?: string;
userEmailKey: string;
enableEmailFormat?: boolean; // Enable email format transformation
userEmailFormat?: string; // Regex pattern to match email
userEmailReplace?: string; // Replacement template using $1, $2, etc.
scope: string;
enableMailAllowList?: boolean | undefined;
mailAllowList?: string[] | undefined;

View File

@@ -68,7 +68,7 @@ export default {
}
const userInfo = await userRes.json<any>()
const email = await (async () => {
const rawEmail = await (async () => {
if (setting.userEmailKey.startsWith("$")) {
const { JSONPath } = await import('jsonpath-plus');
const email = JSONPath({
@@ -83,6 +83,26 @@ export default {
return email;
})()
if (!rawEmail) {
return c.text(msgs.Oauth2FailedGetUserEmailMsg, 400);
}
// Apply email format transformation if enabled
const email = (() => {
const rawEmailStr = String(rawEmail).slice(0, 256).trim(); // 限制长度防止 ReDoS
if (!setting.enableEmailFormat || !setting.userEmailFormat) {
return rawEmailStr;
}
try {
const regex = new RegExp(setting.userEmailFormat);
const replacement = setting.userEmailReplace || '$1';
return rawEmailStr.replace(regex, replacement).trim();
} catch (e) {
console.error(`Invalid regex in userEmailFormat: ${setting.userEmailFormat}`, e);
return rawEmailStr;
}
})();
if (!email) {
return c.text(msgs.Oauth2FailedGetUserEmailMsg, 400);
}