Skip to content

Commit

Permalink
wip: 青龙面板更新,新增支持以应用密钥的方式认证
Browse files Browse the repository at this point in the history
  • Loading branch information
renxia committed Apr 2, 2024
1 parent be44993 commit 466c5e1
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 13 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@
"./template"
],
"dependencies": {
"@lzwme/fe-utils": "^1.7.0",
"@lzwme/fe-utils": "^1.7.2",
"micromatch": "^4.0.5"
},
"devDependencies": {
"@lzwme/fed-lint-helper": "^2.5.2",
"@types/node": "^20.11.22",
"@types/node": "^20.12.2",
"base64-js": "^1.5.1",
"crypto-js": "^4.2.0",
"husky": "^9.0.11",
"prettier": "^3.2.5",
"standard-version": "^9.5.0",
"typescript": "^5.3.3"
"typescript": "^5.4.3"
}
}
44 changes: 37 additions & 7 deletions src/lib/QingLong.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,33 @@
* @Author: renxia
* @Date: 2024-01-18 10:12:52
* @LastEditors: renxia
* @LastEditTime: 2024-02-05 22:52:18
* @LastEditTime: 2024-03-27 09:46:52
* @Description: 青龙面板 API 简易封装
*/
import { existsSync } from 'node:fs';
import { Request, readJsonFileSync, color } from '@lzwme/fe-utils';
import { Request, readJsonFileSync, color, TOTP } from '@lzwme/fe-utils';
import { logger } from './helper';
import { TOTP } from './TOTP';

export class QingLoing {
private static inc: QingLoing;
static getInstance(config?: QLOptions) {
if (!QingLoing.inc) QingLoing.inc = new QingLoing(config);
return QingLoing.inc;
}
private isOpenApi = false;
private loginStatus: number = 0;
private req = new Request('', { 'content-type': 'application/json' });
public async request<T>(method: 'POST' | 'GET' | 'PUT' | 'DELETE', url: string, params?: any): Promise<QLResponse<T>> {
if (!url.startsWith('http')) url = this.config.host + (url.startsWith('/') ? '' : '/') + url;
if (this.isOpenApi) url = url.replace('/api/', '/open/');
const { data } = await this.req.request<QLResponse<T>>(method, url, params);

if (data.code === 401 && this.loginStatus === 1) {
this.loginStatus = 0;
this.config.token = '';
if (await this.login()) return this.request(params, url, params);
}
logger.debug(`[QL][req][${color.cyan(method)}]`, color.gray(url), '\n res:', data, '\n req:', params);
if (this.config.debug) logger.info(`[QL][req][${color.cyan(method)}]`, color.gray(url), '\n req:', params, '\n res:', data);
return data;
}
constructor(private config: QLOptions = {}) {}
Expand All @@ -39,6 +40,7 @@ export class QingLoing {
if (!this.config.host) this.config.host = 'http://127.0.0.1:5700';
if (this.config.host.endsWith('/')) this.config.host = this.config.host.slice(0, -1);

// 尝试从配置文件中读取
for (const filepath of ['/ql/data/config/auth.json', '/ql/config/auth.json']) {
if (existsSync(filepath)) {
const r = readJsonFileSync<{ token: string; username: string; password: string; twoFactorSecret: string }>(filepath);
Expand All @@ -49,16 +51,28 @@ export class QingLoing {
}
}

if (config.clientId && config.clientSecret) {
const data = await this.request<{ token: string }>(
'GET',
`/open/auth/token?client_id=${config.clientId}&client_secret=${config.clientSecret}`
);
if (data.data?.token) {
config.token = data.data.token;
this.isOpenApi = true;
logger.log(`[QL]OpenApi 获取 token 成功!`);
} else logger.error(`[QL]OpenApi 获取 token 异常: ${data.message}`);
}

if (!config.token && !config.username) {
this.loginStatus = -100;
logger.debug('未设置青龙面板相关相关信息');
if (this.config.debug) logger.info('未设置青龙面板相关相关信息');
return false;
}

// 验证 token 有效性
if (this.config.token) {
this.req.setHeaders({ Authorization: `Bearer ${this.config.token}` });
const r = await this.request('GET', `/api/user?t=${Date.now()}`);
const r = await this.request<QLEnvItem[]>('GET', `/api/envs?searchValue=&t=${Date.now()}`);
if (r.code !== 200) {
logger.warn('token 已失效:', r);
this.config.token = '';
Expand Down Expand Up @@ -141,7 +155,23 @@ export class QingLoing {
}
}

export type QLOptions = { host?: string; token?: string; username?: string; password?: string; twoFactorSecret?: string };
export type QLOptions = {
debug?: boolean;
/** 青龙服务地址。用于上传环境变量,若设置为空则不上传 */
host?: string;
/** 青龙服务 token。用于创建或更新 QL 环境变量配置。会自动尝试从 /ql/data/config/auth.json 文件中获取 */
token?: string;
/** 登录用户名 */
username?: string;
/** 登录密码 */
password?: string;
/** 两步验证秘钥。若开启了两步验证则需设置 */
twoFactorSecret?: string;
/** open app client_id: 应用设置-创建应用,权限选择 环境变量 */
clientId?: string;
/** open app client_secret */
clientSecret?: string;
};
export type QLEnvItem = { name: string; value: string; id?: string; remarks: string };
export type QLResponse<T = any> = { code: number; message: string; data: T };
export interface QLTaskItem {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: renxia
* @Date: 2024-01-11 13:38:34
* @LastEditors: renxia
* @LastEditTime: 2024-03-22 10:44:22
* @LastEditTime: 2024-03-27 09:48:16
* @Description:
*/
import fs from 'node:fs';
Expand All @@ -18,7 +18,7 @@ const updateCache = { qlEnvList: [] as QLEnvItem[], updateTime: 0 };

export async function updateToQlEnvConfig({ name, value, desc }: EnvConfig, updateEnvValue?: RuleItem['updateEnvValue']) {
const config = getConfig();
const ql = QingLoing.getInstance(config.ql);
const ql = QingLoing.getInstance({ ...config.ql, debug: config.debug });
if (!(await ql.login())) return;

if (Date.now() - updateCache.updateTime > 1000 * 60 * 60 * 1) updateCache.qlEnvList = [];
Expand Down
6 changes: 5 additions & 1 deletion typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: renxia
* @Date: 2024-01-11 16:53:50
* @LastEditors: renxia
* @LastEditTime: 2024-03-01 15:57:52
* @LastEditTime: 2024-03-26 11:16:17
* @Description:
*/
/// <reference path="global.d.ts" />
Expand Down Expand Up @@ -31,6 +31,10 @@ export interface W2XScriptsConfig {
password?: string;
/** 两步验证秘钥。若开启了两步验证则需设置 */
twoFactorSecret?: string;
/** open app client_id: 应用设置-创建应用,权限选择 环境变量 */
clientId?: string;
/** open app client_secret */
clientSecret?: string;
};
/** 写入环境变量信息到本地文件的路径。若设置为空则不写入 */
envConfFile?: string;
Expand Down

0 comments on commit 466c5e1

Please sign in to comment.