auth.mjs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /**
  2. * 更新发布工具 - 认证与服务器连接模块
  3. *
  4. * Copyright © 2025 imengyu.top imengyu-update-server
  5. */
  6. import { readFile, writeFile } from 'node:fs/promises';
  7. import path from 'node:path';
  8. import { dirname } from 'node:path';
  9. import { fileURLToPath } from 'node:url';
  10. import axios from 'axios';
  11. import md5 from 'md5';
  12. import { password } from '@inquirer/prompts';
  13. import { config } from './postConfig.mjs';
  14. // 基础配置
  15. // ========================================
  16. const __filename = fileURLToPath(import.meta.url);
  17. const __dirname = dirname(__filename);
  18. export const constant = {
  19. ServerUrl: config.server,
  20. TokenSave: path.resolve(__dirname, './_token.json'),
  21. };
  22. let currentData = {
  23. token: '',
  24. identifier: '',
  25. };
  26. function initIdentifier() {
  27. if (!currentData.identifier)
  28. currentData.identifier = `commandClient${Math.floor(Math.random() * 1000)}`;
  29. }
  30. function getErrorMessage(e) {
  31. return e instanceof Error ? e.message : (typeof e === 'object' ? e : '' + e);
  32. }
  33. // Axios 实例
  34. // ========================================
  35. export const axiosInstance = axios.create({
  36. baseURL: constant.ServerUrl,
  37. timeoutErrorMessage: '请求超时,请检查网络连接',
  38. responseType: 'json',
  39. withCredentials: false,
  40. validateStatus: () => true,
  41. });
  42. axiosInstance.interceptors.request.use((value) => {
  43. value.headers['authorization'] = JSON.stringify({
  44. auth: currentData?.token?.authName,
  45. validity: currentData?.token?.authKey,
  46. nonce: 'aaaaaaaaaa',
  47. identifier: currentData.identifier,
  48. key: 'abc123',
  49. });
  50. value.url =
  51. value.url +
  52. (value.url.includes('?') ? '&' : '?') +
  53. `identifier=${currentData.identifier}`;
  54. return value;
  55. });
  56. axiosInstance.interceptors.response.use((value) => {
  57. if (value.data.success) return value.data;
  58. else return Promise.reject(value.data);
  59. });
  60. // 认证初始化
  61. // ========================================
  62. /**
  63. * 初始化认证模块,从本地加载 token
  64. * @returns {Promise<void>}
  65. */
  66. export async function initAuth() {
  67. try {
  68. const res = await readFile(constant.TokenSave);
  69. const parsed = JSON.parse(res);
  70. if (parsed && typeof parsed === 'object') {
  71. currentData = { ...currentData, ...parsed };
  72. }
  73. } catch {
  74. // 无 token 文件时使用默认值
  75. }
  76. initIdentifier();
  77. }
  78. /**
  79. * 获取当前认证数据(只读)
  80. */
  81. export function getCurrentData() {
  82. return { ...currentData };
  83. }
  84. // 登录相关
  85. // ========================================
  86. /**
  87. * 检查登录状态
  88. */
  89. export async function checkLogged() {
  90. try {
  91. await axiosInstance.get('/auth');
  92. console.log('已登录');
  93. } catch (e) {
  94. console.error('获取状态失败:', getErrorMessage(e));
  95. }
  96. }
  97. /**
  98. * 登录
  99. * @param {string} user 用户名
  100. */
  101. export async function login(user) {
  102. try {
  103. const pass = await password({ message: '输入密码' });
  104. const res = await axiosInstance.post('/auth?rember=true', {
  105. method: 'key',
  106. key: `${user}@${md5(pass)}`,
  107. });
  108. currentData.token = {
  109. authName: res.data.authName,
  110. authKey: res.data.authKey,
  111. };
  112. await writeFile(constant.TokenSave, JSON.stringify(currentData));
  113. console.log('登录成功');
  114. } catch (e) {
  115. console.error('登录失败', getErrorMessage(e));
  116. }
  117. }
  118. /**
  119. * 退出登录
  120. */
  121. export async function logout() {
  122. currentData.token = '';
  123. await writeFile(constant.TokenSave, JSON.stringify(currentData));
  124. try {
  125. await axiosInstance.delete('/auth');
  126. console.log('退出登录成功');
  127. } catch (e) {
  128. console.error('退出登录失败', getErrorMessage(e));
  129. }
  130. }