mirror of
				https://github.com/whyour/qinglong.git
				synced 2025-11-04 11:16:07 +08:00 
			
		
		
		
	修复重置登录错误次数和 tfa
This commit is contained in:
		
							parent
							
								
									cecc5aeb15
								
							
						
					
					
						commit
						7d43b14f81
					
				| 
						 | 
				
			
			@ -377,4 +377,23 @@ export default (app: Router) => {
 | 
			
		|||
      }
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  route.put(
 | 
			
		||||
    '/auth/reset',
 | 
			
		||||
    celebrate({
 | 
			
		||||
      body: Joi.object({
 | 
			
		||||
        retries: Joi.number().optional(),
 | 
			
		||||
        twoFactorActivated: Joi.boolean().optional(),
 | 
			
		||||
      }),
 | 
			
		||||
    }),
 | 
			
		||||
    async (req: Request, res: Response, next: NextFunction) => {
 | 
			
		||||
      try {
 | 
			
		||||
        const userService = Container.get(UserService);
 | 
			
		||||
        await userService.resetAuthInfo(req.body);
 | 
			
		||||
        res.send({ code: 200, message: '更新成功' });
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        return next(e);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,7 +59,6 @@ export interface AuthInfo {
 | 
			
		|||
  token: string;
 | 
			
		||||
  tokens: Record<string, string>;
 | 
			
		||||
  twoFactorActivated: boolean;
 | 
			
		||||
  twoFactorActived: boolean;
 | 
			
		||||
  twoFactorSecret: string;
 | 
			
		||||
  avatar: string;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@ import { writeFile, readFile } from 'fs/promises';
 | 
			
		|||
import { safeJSONParse } from '../config/util';
 | 
			
		||||
import OpenService from '../services/open';
 | 
			
		||||
import { shareStore } from '../shared/store';
 | 
			
		||||
import Logger from './logger';
 | 
			
		||||
 | 
			
		||||
export default async () => {
 | 
			
		||||
  const cronService = Container.get(CronService);
 | 
			
		||||
| 
						 | 
				
			
			@ -26,16 +27,13 @@ export default async () => {
 | 
			
		|||
  const openService = Container.get(OpenService);
 | 
			
		||||
 | 
			
		||||
  // 初始化增加系统配置
 | 
			
		||||
  await SystemModel.findOrCreate({
 | 
			
		||||
  const [systemConfig] = await SystemModel.findOrCreate({
 | 
			
		||||
    where: { type: AuthDataType.systemConfig },
 | 
			
		||||
  });
 | 
			
		||||
  await SystemModel.findOrCreate({
 | 
			
		||||
  const [notifyConfig] = await SystemModel.findOrCreate({
 | 
			
		||||
    where: { type: AuthDataType.notification },
 | 
			
		||||
  });
 | 
			
		||||
  await SystemModel.findOrCreate({
 | 
			
		||||
    where: { type: AuthDataType.authConfig },
 | 
			
		||||
  });
 | 
			
		||||
  const authConfig = await SystemModel.findOne({
 | 
			
		||||
  const [authConfig] = await SystemModel.findOrCreate({
 | 
			
		||||
    where: { type: AuthDataType.authConfig },
 | 
			
		||||
  });
 | 
			
		||||
  if (!authConfig?.info) {
 | 
			
		||||
| 
						 | 
				
			
			@ -46,25 +44,20 @@ export default async () => {
 | 
			
		|||
    try {
 | 
			
		||||
      const content = await readFile(config.authConfigFile, 'utf8');
 | 
			
		||||
      authInfo = safeJSONParse(content);
 | 
			
		||||
    } catch (error) {}
 | 
			
		||||
    if (authConfig?.id) {
 | 
			
		||||
      await SystemModel.update(
 | 
			
		||||
        { info: authInfo },
 | 
			
		||||
        {
 | 
			
		||||
          where: { id: authConfig.id },
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
    } else {
 | 
			
		||||
      await SystemModel.create({
 | 
			
		||||
        info: authInfo,
 | 
			
		||||
        type: AuthDataType.authConfig,
 | 
			
		||||
      });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      Logger.warn('Failed to read auth config file, using default credentials');
 | 
			
		||||
    }
 | 
			
		||||
    await SystemModel.upsert({
 | 
			
		||||
      id: authConfig?.id,
 | 
			
		||||
      info: authInfo,
 | 
			
		||||
      type: AuthDataType.authConfig,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 初始化通知配置
 | 
			
		||||
  const notifyConfig = await userService.getNotificationMode();
 | 
			
		||||
  await writeFile(config.systemNotifyFile, JSON.stringify(notifyConfig));
 | 
			
		||||
  if (notifyConfig.info) {
 | 
			
		||||
    await writeFile(config.systemNotifyFile, JSON.stringify(notifyConfig.info));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const installDependencies = () => {
 | 
			
		||||
    // 初始化时安装所有处于安装中,安装成功,安装失败的依赖
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +80,6 @@ export default async () => {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  // 初始化更新 linux/python/nodejs 镜像源配置
 | 
			
		||||
  const systemConfig = await systemService.getSystemConfig();
 | 
			
		||||
  if (systemConfig.info?.pythonMirror) {
 | 
			
		||||
    systemService.updatePythonMirror({
 | 
			
		||||
      pythonMirror: systemConfig.info?.pythonMirror,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ export default class OpenService {
 | 
			
		|||
    tab.client_id = createRandomString(12, 12);
 | 
			
		||||
    tab.client_secret = createRandomString(24, 24);
 | 
			
		||||
    const doc = await this.insert(tab);
 | 
			
		||||
    const apps = await this.find({});
 | 
			
		||||
    await shareStore.updateApps(apps);
 | 
			
		||||
    return { ...doc, tokens: [] };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +56,8 @@ export default class OpenService {
 | 
			
		|||
 | 
			
		||||
  public async remove(ids: number[]) {
 | 
			
		||||
    await AppModel.destroy({ where: { id: ids } });
 | 
			
		||||
    const apps = await this.find({});
 | 
			
		||||
    await shareStore.updateApps(apps);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async resetSecret(id: number): Promise<App> {
 | 
			
		||||
| 
						 | 
				
			
			@ -136,6 +140,8 @@ export default class OpenService {
 | 
			
		|||
        { tokens },
 | 
			
		||||
        { where: { client_id, client_secret } },
 | 
			
		||||
      );
 | 
			
		||||
      const apps = await this.find({});
 | 
			
		||||
      await shareStore.updateApps(apps);
 | 
			
		||||
      return {
 | 
			
		||||
        code: 200,
 | 
			
		||||
        data: {
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +151,7 @@ export default class OpenService {
 | 
			
		|||
        },
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      return { code: 400, message: 'client_id或client_seret有误' };
 | 
			
		||||
      return { code: 400, message: 'client_id 或 client_seret 有误' };
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,15 +159,9 @@ export default class OpenService {
 | 
			
		|||
    value: string;
 | 
			
		||||
    expiration: number;
 | 
			
		||||
  }> {
 | 
			
		||||
    let systemApp = (await AppModel.findOne({
 | 
			
		||||
      where: { name: 'system' },
 | 
			
		||||
    })) as App;
 | 
			
		||||
    if (!systemApp) {
 | 
			
		||||
      systemApp = await this.create({
 | 
			
		||||
        name: 'system',
 | 
			
		||||
        scopes: ['crons', 'system'],
 | 
			
		||||
      } as App);
 | 
			
		||||
    }
 | 
			
		||||
    const [systemApp] = await AppModel.findOrCreate({
 | 
			
		||||
      where: { name: 'system', scopes: ['crons', 'system'] },
 | 
			
		||||
    });
 | 
			
		||||
    const { data } = await this.authToken({
 | 
			
		||||
      client_id: systemApp.client_id,
 | 
			
		||||
      client_secret: systemApp.client_secret,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,13 +61,9 @@ export default class UserService {
 | 
			
		|||
      lastip,
 | 
			
		||||
      lastaddr,
 | 
			
		||||
      twoFactorActivated,
 | 
			
		||||
      twoFactorActived,
 | 
			
		||||
      tokens = {},
 | 
			
		||||
      platform,
 | 
			
		||||
    } = content;
 | 
			
		||||
    // patch old field
 | 
			
		||||
    twoFactorActivated = twoFactorActivated || twoFactorActived;
 | 
			
		||||
 | 
			
		||||
    const retriesTime = Math.pow(3, retries) * 1000;
 | 
			
		||||
    if (retries > 2 && timestamp - lastlogon < retriesTime) {
 | 
			
		||||
      const waitTime = Math.ceil(
 | 
			
		||||
| 
						 | 
				
			
			@ -215,20 +211,6 @@ export default class UserService {
 | 
			
		|||
    return doc;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async initAuthInfo() {
 | 
			
		||||
    await fs.writeFile(
 | 
			
		||||
      config.authConfigFile,
 | 
			
		||||
      JSON.stringify({
 | 
			
		||||
        username: 'admin',
 | 
			
		||||
        password: 'admin',
 | 
			
		||||
      }),
 | 
			
		||||
    );
 | 
			
		||||
    return {
 | 
			
		||||
      code: 100,
 | 
			
		||||
      message: '未找到认证文件,重新初始化',
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async updateUsernameAndPassword({
 | 
			
		||||
    username,
 | 
			
		||||
    password,
 | 
			
		||||
| 
						 | 
				
			
			@ -304,7 +286,6 @@ export default class UserService {
 | 
			
		|||
    const authInfo = await this.getAuthInfo();
 | 
			
		||||
    await this.updateAuthInfo(authInfo, {
 | 
			
		||||
      twoFactorActivated: false,
 | 
			
		||||
      twoFactorActived: false,
 | 
			
		||||
      twoFactorSecret: '',
 | 
			
		||||
    });
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -319,7 +300,7 @@ export default class UserService {
 | 
			
		|||
    return (doc.info || {}) as AuthInfo;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async updateAuthInfo(authInfo: any, info: any) {
 | 
			
		||||
  private async updateAuthInfo(authInfo: AuthInfo, info: Partial<AuthInfo>) {
 | 
			
		||||
    const result = { ...authInfo, ...info };
 | 
			
		||||
    await shareStore.updateAuthInfo(result);
 | 
			
		||||
    await this.updateAuthDb({
 | 
			
		||||
| 
						 | 
				
			
			@ -372,4 +353,13 @@ export default class UserService {
 | 
			
		|||
      return { code: 400, message: '通知发送失败,请检查参数' };
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async resetAuthInfo(info: Partial<AuthInfo>) {
 | 
			
		||||
    const { retries, twoFactorActivated } = info;
 | 
			
		||||
    const authInfo = await this.getAuthInfo();
 | 
			
		||||
    await this.updateAuthInfo(authInfo, {
 | 
			
		||||
      retries,
 | 
			
		||||
      twoFactorActivated,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								shell/api.sh
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								shell/api.sh
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -231,4 +231,30 @@ find_cron_api() {
 | 
			
		|||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
update_auth_config() {
 | 
			
		||||
  local body="$1"
 | 
			
		||||
  local tip="$2"
 | 
			
		||||
  local currentTimeStamp=$(date +%s)
 | 
			
		||||
  local api=$(
 | 
			
		||||
    curl -s --noproxy "*" "http://0.0.0.0:5600/open/system/auth/reset?t=$currentTimeStamp" \
 | 
			
		||||
      -X 'PUT' \
 | 
			
		||||
      -H "Accept: application/json" \
 | 
			
		||||
      -H "Authorization: Bearer ${__ql_token__}" \
 | 
			
		||||
      -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" \
 | 
			
		||||
      -H "Content-Type: application/json;charset=UTF-8" \
 | 
			
		||||
      -H "Origin: http://0.0.0.0:5700" \
 | 
			
		||||
      -H "Referer: http://0.0.0.0:5700/crontab" \
 | 
			
		||||
      -H "Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" \
 | 
			
		||||
      --data-raw "{$body}" \
 | 
			
		||||
      --compressed
 | 
			
		||||
  )
 | 
			
		||||
  code=$(echo "$api" | jq -r .code)
 | 
			
		||||
  message=$(echo "$api" | jq -r .message)
 | 
			
		||||
  if [[ $code == 200 ]]; then
 | 
			
		||||
    echo -e "${tip}成功🎉"
 | 
			
		||||
  else
 | 
			
		||||
    echo -e "${tip}失败(${message})"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
get_token
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -537,14 +537,10 @@ main() {
 | 
			
		|||
    eval . $dir_shell/check.sh $cmd
 | 
			
		||||
    ;;
 | 
			
		||||
  resetlet)
 | 
			
		||||
    auth_value=$(cat $file_auth_user | jq '.retries =0' -c)
 | 
			
		||||
    echo "$auth_value" >$file_auth_user
 | 
			
		||||
    eval echo -e "重置登录错误次数成功" $cmd
 | 
			
		||||
    eval update_auth_config "\\\"retries\\\":0" "重置登录错误次数" $cmd
 | 
			
		||||
    ;;
 | 
			
		||||
  resettfa)
 | 
			
		||||
    auth_value=$(cat $file_auth_user | jq '.twoFactorActivated =false' | jq '.twoFactorActived =false' -c)
 | 
			
		||||
    echo "$auth_value" >$file_auth_user
 | 
			
		||||
    eval echo -e "禁用两步验证成功" $cmd
 | 
			
		||||
    eval update_auth_config "\\\"twoFactorActivated\\\":false" "禁用两步验证" $cmd
 | 
			
		||||
    ;;
 | 
			
		||||
  *)
 | 
			
		||||
    eval echo -e "命令输入错误...\\\n" $cmd
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user