fix: #102 fix non-email github account login cannot register problem

use generated email to register if email not include

and migrate other generated email to same format
pull/105/head
moonrailgun 2 years ago
parent 0924fa617a
commit a0cbc45760

@ -24,11 +24,11 @@ import {
} from 'tailchat-shared'; } from 'tailchat-shared';
import { EmailVerify } from '../EmailVerify'; import { EmailVerify } from '../EmailVerify';
import { ModifyPassword } from '../ModifyPassword'; import { ModifyPassword } from '../ModifyPassword';
import { isBuiltinEmail } from '@/utils/user-helper';
export const SettingsAccount: React.FC = React.memo(() => { export const SettingsAccount: React.FC = React.memo(() => {
const userInfo = useUserInfo(); const userInfo = useUserInfo();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const navigate = useNavigate();
const userExtra = userInfo?.extra ?? {}; const userExtra = userInfo?.extra ?? {};
const [, handleUserAvatarChange] = useAsyncRequest( const [, handleUserAvatarChange] = useAsyncRequest(
@ -113,7 +113,11 @@ export const SettingsAccount: React.FC = React.memo(() => {
content={ content={
<div> <div>
<span className="mr-1">{userInfo.email}</span> <span className="mr-1">{userInfo.email}</span>
{userInfo.emailVerified ? ( {isBuiltinEmail(userInfo.email) ? (
<Tag color="default" className="select-none">
{t('内置邮箱')}
</Tag>
) : userInfo.emailVerified ? (
<Tag color="success" className="select-none"> <Tag color="success" className="select-none">
{t('已认证')} {t('已认证')}
</Tag> </Tag>

@ -39,3 +39,28 @@ export async function tryAutoLogin(): Promise<UserLoginInfo> {
return userLoginInfo; return userLoginInfo;
} }
/**
*
*
*
* iam
*/
export function isBuiltinEmail(email: string): boolean {
if (typeof email !== 'string') {
// 一般来说内置邮箱都是表示不可用状态因此如果不是合法输入直接视为true
return true;
}
const domain = email.split('@')[1];
if (!domain) {
return true;
}
if (domain.endsWith('.msgbyte.com')) {
return true;
}
return false;
}

@ -84,9 +84,14 @@ class IAMService extends TcService {
}); });
} }
const username = providerUserInfo.username;
const email =
providerUserInfo.email ||
`${username}.${strategyName}@iam.msgbyte.com`;
// 不存在记录,查找是否已经注册过,如果已经注册过需要绑定,如果没有注册过则创建账号并绑定用户关系 // 不存在记录,查找是否已经注册过,如果已经注册过需要绑定,如果没有注册过则创建账号并绑定用户关系
const userInfo = await ctx.call('user.findUserByEmail', { const userInfo = await ctx.call('user.findUserByEmail', {
email: providerUserInfo.email, email,
}); });
if (!!userInfo) { if (!!userInfo) {
// 用户已存在,需要登录后才能确定绑定关系 // 用户已存在,需要登录后才能确定绑定关系
@ -114,7 +119,7 @@ class IAMService extends TcService {
const newUserInfo: UserStructWithToken = await ctx.call( const newUserInfo: UserStructWithToken = await ctx.call(
'user.register', 'user.register',
{ {
email: providerUserInfo.email, email,
nickname: providerUserInfo.nickname, nickname: providerUserInfo.nickname,
password: String(new db.Types.ObjectId()), // random password password: String(new db.Types.ObjectId()), // random password
avatar, avatar,

@ -46,13 +46,20 @@ export const GithubStrategy: StrategyType = {
Authorization: `token ${accessToken}`, Authorization: `token ${accessToken}`,
}, },
}) })
.json<{ id: number; name: string; email: string; avatar_url: string }>(); .json<{
id: number;
login: string;
name: string;
email: string;
avatar_url: string;
}>();
console.log(`[github oauth] user info:`, result); console.log(`[github oauth] user info:`, result);
return { return {
id: String(result.id), id: String(result.id),
nickname: result.name, nickname: result.name,
username: result.login,
email: result.email, email: result.email,
avatar: result.avatar_url, avatar: result.avatar_url,
}; };

@ -7,6 +7,7 @@ export interface StrategyType {
getUserInfo: (code: string) => Promise<{ getUserInfo: (code: string) => Promise<{
id: string; id: string;
nickname: string; nickname: string;
username: string;
email: string; email: string;
avatar: string; avatar: string;
}>; }>;

@ -30,6 +30,8 @@ export const IAMAction: React.FC = React.memo(() => {
if (payload.type === 'existed') { if (payload.type === 'existed') {
showToasts(Translate.accountExistedTip, 'warning'); showToasts(Translate.accountExistedTip, 'warning');
} else if (payload.type === 'infoDeviant') {
showToasts(Translate.infoDeviantTip, 'error');
} else if (payload.type === 'token') { } else if (payload.type === 'token') {
const token = payload.token; const token = payload.token;
setUserJWT(token) setUserJWT(token)

@ -15,6 +15,12 @@ export const Translate = {
'zh-CN': '账号已存在,请使用账号密码登录', 'zh-CN': '账号已存在,请使用账号密码登录',
'en-US': 'Account Existed, please log in with account password', 'en-US': 'Account Existed, please log in with account password',
}), }),
infoDeviantTip: localTrans({
// 'zh-CN': '账号已存在,你应该在登录后绑定账号',
// 'en-US': 'Account Existed, You should bind provider account after login',
'zh-CN': '账号信息异常,请使用账号密码登录',
'en-US': 'Account Info Deviant, please log in with account password',
}),
notSupportMobile: localTrans({ notSupportMobile: localTrans({
'zh-CN': '第三方登录功能暂不支持移动端使用', 'zh-CN': '第三方登录功能暂不支持移动端使用',
'en-US': 'The third-party login function does not support mobile use', 'en-US': 'The third-party login function does not support mobile use',

@ -200,6 +200,12 @@ class UserService extends TcService {
email: 'string', email: 'string',
}, },
}); });
this.registerAction('findUserByUsername', this.findUserByUsername, {
visibility: 'public',
params: {
username: 'string',
},
});
this.registerAction('updateUserField', this.updateUserField, { this.registerAction('updateUserField', this.updateUserField, {
params: { params: {
fieldName: 'string', fieldName: 'string',
@ -537,7 +543,7 @@ class UserService extends TcService {
const password = await this.hashPassword(generateRandomStr()); const password = await this.hashPassword(generateRandomStr());
const doc = await this.adapter.insert({ const doc = await this.adapter.insert({
email: `${generateRandomStr()}.temporary@msgbyte.com`, email: `${generateRandomStr()}@temporary.msgbyte.com`,
password, password,
nickname, nickname,
discriminator, discriminator,
@ -861,6 +867,29 @@ class UserService extends TcService {
return user; return user;
} }
/**
*
*/
async findUserByUsername(
ctx: TcContext<{
username: string;
}>
): Promise<UserStruct | null> {
const username = ctx.params.username;
const doc = await this.adapter.model.findOne({
username,
});
if (!doc) {
return null;
}
const user = await this.transformDocuments(ctx, {}, doc);
return user;
}
/** /**
* *
*/ */
@ -1073,7 +1102,7 @@ class UserService extends TcService {
} }
/** /**
* id * id
*/ */
findOpenapiBotId(ctx: TcContext<{ email: string }>): string { findOpenapiBotId(ctx: TcContext<{ email: string }>): string {
return this.parseOpenapiBotEmail(ctx.params.email); return this.parseOpenapiBotEmail(ctx.params.email);
@ -1216,18 +1245,23 @@ class UserService extends TcService {
} }
private buildPluginBotEmail(botId: string) { private buildPluginBotEmail(botId: string) {
return `${botId}@tailchat-plugin.com`; return `${botId}@plugin.msgbyte.com`;
} }
private buildOpenapiBotEmail(botId: string) { private buildOpenapiBotEmail(botId: string) {
return `${botId}@tailchat-openapi.com`; return `${botId}@openapi.msgbyte.com`;
} }
private parseOpenapiBotEmail(email: string): string | null { private parseOpenapiBotEmail(email: string): string | null {
if (email.endsWith('@tailchat-openapi.com')) { if (email.endsWith('@tailchat-openapi.com')) {
// 旧的实现,兼容代码
return email.replace('@tailchat-openapi.com', ''); return email.replace('@tailchat-openapi.com', '');
} }
if (email.endsWith('@openapi.msgbyte.com')) {
return email.replace('@openapi.msgbyte.com', '');
}
return null; return null;
} }

Loading…
Cancel
Save