@wps-agent/wps-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/api/client.d.ts +374 -0
  2. package/dist/api/client.d.ts.map +1 -0
  3. package/dist/api/client.js +566 -0
  4. package/dist/api/client.js.map +1 -0
  5. package/dist/auth/providers/base.d.ts +23 -0
  6. package/dist/auth/providers/base.d.ts.map +1 -0
  7. package/dist/auth/providers/base.js +43 -0
  8. package/dist/auth/providers/base.js.map +1 -0
  9. package/dist/auth/providers/wps.d.ts +108 -0
  10. package/dist/auth/providers/wps.d.ts.map +1 -0
  11. package/dist/auth/providers/wps.js +242 -0
  12. package/dist/auth/providers/wps.js.map +1 -0
  13. package/dist/auth/server.d.ts +50 -0
  14. package/dist/auth/server.d.ts.map +1 -0
  15. package/dist/auth/server.js +251 -0
  16. package/dist/auth/server.js.map +1 -0
  17. package/dist/auth/storage/file.d.ts +70 -0
  18. package/dist/auth/storage/file.d.ts.map +1 -0
  19. package/dist/auth/storage/file.js +120 -0
  20. package/dist/auth/storage/file.js.map +1 -0
  21. package/dist/auth/storage/interface.d.ts +14 -0
  22. package/dist/auth/storage/interface.d.ts.map +1 -0
  23. package/dist/auth/storage/interface.js +5 -0
  24. package/dist/auth/storage/interface.js.map +1 -0
  25. package/dist/index.d.ts +16 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +17 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/types/api-client.d.ts +229 -0
  30. package/dist/types/api-client.d.ts.map +1 -0
  31. package/dist/types/api-client.js +7 -0
  32. package/dist/types/api-client.js.map +1 -0
  33. package/dist/types/index.d.ts +5 -0
  34. package/dist/types/index.d.ts.map +1 -0
  35. package/dist/types/index.js +7 -0
  36. package/dist/types/index.js.map +1 -0
  37. package/package.json +53 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/auth/providers/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,OAAgB,kBAAkB;IAE1B;IACA;IAFZ,YACY,MAAoB,EACpB,UAET;QAHS,WAAM,GAAN,MAAM,CAAc;QACpB,eAAU,GAAV,UAAU,CAEnB;IACA,CAAC;IAEJ,mBAAmB,CAAC,KAAc;QAChC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;YAChC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YACtC,aAAa,EAAE,MAAM;YACrB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;SACpC,CAAC,CAAC;QAEH,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,IAAY;QACrC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;YACjE,UAAU,EAAE,oBAAoB;YAChC,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;YAChC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;YACxC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;SACvC,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;YACjE,UAAU,EAAE,eAAe;YAC3B,aAAa,EAAE,YAAY;YAC3B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;YAChC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;SACzC,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;CAIF"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * 金山文档 OAuth2.0 认证提供商
3
+ *
4
+ * 实现完整的 OAuth2.0 授权码模式流程
5
+ */
6
+ import { BaseOAuth2Provider } from './base.js';
7
+ import type { OAuth2Config, TokenResponse, TokenStorage } from '@wps-agent/shared';
8
+ export interface WpsOAuth2Config extends OAuth2Config {
9
+ apiUrl?: string;
10
+ }
11
+ export interface WpsAuthProviderOptions {
12
+ client_id: string;
13
+ client_secret: string;
14
+ redirect_uri: string;
15
+ scopes?: string[];
16
+ /**
17
+ * Token 存储方式,默认使用文件存储
18
+ */
19
+ tokenStorage?: TokenStorage;
20
+ /**
21
+ * Token 存储文件路径(仅当使用默认文件存储时有效)
22
+ */
23
+ tokenStoragePath?: string;
24
+ }
25
+ /**
26
+ * WPS Token 响应(包含完整信息)
27
+ */
28
+ export interface WpsTokenResponse extends TokenResponse {
29
+ access_token: string;
30
+ token_type: 'Bearer';
31
+ expires_in: number;
32
+ refresh_token?: string;
33
+ }
34
+ export declare class WpsAuthProvider extends BaseOAuth2Provider {
35
+ private tokenStorage;
36
+ constructor(options: WpsAuthProviderOptions);
37
+ /**
38
+ * 生成授权 URL
39
+ *
40
+ * @param state - 自定义参数,用于防止 CSRF 攻击
41
+ * @returns 授权 URL,用户需要在浏览器中访问此 URL 进行授权
42
+ */
43
+ getAuthorizationUrl(state?: string): string;
44
+ /**
45
+ * 用授权码换取 access_token
46
+ *
47
+ * @param code - 临时授权码,从回调 URL 中获取
48
+ * @returns Token 响应
49
+ */
50
+ exchangeCodeForToken(code: string): Promise<TokenResponse>;
51
+ /**
52
+ * 刷新 access_token
53
+ *
54
+ * @param refreshToken - 刷新令牌
55
+ * @returns 新的 Token 响应
56
+ */
57
+ refreshToken(refreshToken: string): Promise<TokenResponse>;
58
+ /**
59
+ * 验证 token 是否有效
60
+ *
61
+ * @param token - access_token
62
+ * @returns token 是否有效
63
+ */
64
+ validateToken(token: string): Promise<boolean>;
65
+ /**
66
+ * 撤销 token
67
+ *
68
+ * @param token - access_token
69
+ */
70
+ revokeToken(token: string): Promise<void>;
71
+ /**
72
+ * 保存 token 到存储
73
+ *
74
+ * @param key - 缓存键(通常是用户 ID)
75
+ * @param token - Token 响应
76
+ */
77
+ saveToken(key: string, token: TokenResponse): Promise<void>;
78
+ /**
79
+ * 从存储中获取 token
80
+ *
81
+ * @param key - 缓存键
82
+ * @returns Token,如果不存在或已过期返回 null
83
+ */
84
+ getToken(key: string): Promise<any>;
85
+ /**
86
+ * 从回调 URL 中提取授权码
87
+ *
88
+ * @param callbackUrl - 回调 URL,格式: redirect_uri?code=xxx&state=xxx
89
+ * @returns 授权码
90
+ */
91
+ extractCodeFromCallback(callbackUrl: string): string;
92
+ /**
93
+ * 从回调 URL 中提取 state 参数
94
+ *
95
+ * @param callbackUrl - 回调 URL
96
+ * @returns state 参数
97
+ */
98
+ extractStateFromCallback(callbackUrl: string): string | null;
99
+ /**
100
+ * 删除指定 key 的 token
101
+ */
102
+ removeToken(key: string): Promise<void>;
103
+ /**
104
+ * 清空所有 token
105
+ */
106
+ clearAllTokens(): Promise<void>;
107
+ }
108
+ //# sourceMappingURL=wps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wps.d.ts","sourceRoot":"","sources":["../../../src/auth/providers/wps.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGnF,MAAM,WAAW,eAAgB,SAAQ,YAAY;IAEnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,QAAQ,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,eAAgB,SAAQ,kBAAkB;IACrD,OAAO,CAAC,YAAY,CAAe;gBAEvB,OAAO,EAAE,sBAAsB;IAuD3C;;;;;OAKG;IACH,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAe3C;;;;;OAKG;IACG,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAgBhE;;;;;OAKG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAehE;;;;;OAKG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAcpD;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe/C;;;;;OAKG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IASjE;;;;;OAKG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAwCzC;;;;;OAKG;IACH,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAWpD;;;;;OAKG;IACH,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAK5D;;OAEG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;CAGtC"}
@@ -0,0 +1,242 @@
1
+ /**
2
+ * 金山文档 OAuth2.0 认证提供商
3
+ *
4
+ * 实现完整的 OAuth2.0 授权码模式流程
5
+ */
6
+ import { BaseOAuth2Provider } from './base.js';
7
+ import { FileTokenStorage } from '../storage/file.js';
8
+ export class WpsAuthProvider extends BaseOAuth2Provider {
9
+ tokenStorage;
10
+ constructor(options) {
11
+ // 金山文档 OAuth2.0 配置
12
+ const defaultConfig = {
13
+ client_id: options.client_id,
14
+ client_secret: options.client_secret,
15
+ redirect_uri: options.redirect_uri,
16
+ scopes: ['kso.airpage.readwrite', 'kso.documents.readwrite'],
17
+ // 金山文档的 OAuth2.0 端点
18
+ authorization_url: 'https://openapi.wps.cn/oauth2/auth',
19
+ token_url: 'https://openapi.wps.cn/oauth2/token',
20
+ };
21
+ // 实现 HTTP 客户端,使用 application/x-www-form-urlencoded
22
+ const httpClient = {
23
+ post: async (url, data) => {
24
+ // 使用 URLSearchParams 编码表单数据
25
+ const formData = new URLSearchParams(data);
26
+ const response = await fetch(url, {
27
+ method: 'POST',
28
+ headers: {
29
+ 'Content-Type': 'application/x-www-form-urlencoded',
30
+ },
31
+ body: formData.toString(),
32
+ });
33
+ if (!response.ok) {
34
+ const errorText = await response.text();
35
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
36
+ }
37
+ const result = (await response.json());
38
+ // 转换为标准 TokenResponse 格式
39
+ return {
40
+ data: {
41
+ access_token: result.access_token,
42
+ refresh_token: result.refresh_token,
43
+ expires_in: result.expires_in,
44
+ token_type: result.token_type,
45
+ },
46
+ };
47
+ },
48
+ };
49
+ super(defaultConfig, httpClient);
50
+ // 初始化 Token 存储
51
+ this.tokenStorage =
52
+ options.tokenStorage ||
53
+ new FileTokenStorage({
54
+ filePath: options.tokenStoragePath,
55
+ });
56
+ }
57
+ /**
58
+ * 生成授权 URL
59
+ *
60
+ * @param state - 自定义参数,用于防止 CSRF 攻击
61
+ * @returns 授权 URL,用户需要在浏览器中访问此 URL 进行授权
62
+ */
63
+ getAuthorizationUrl(state) {
64
+ const params = new URLSearchParams({
65
+ response_type: 'code',
66
+ client_id: this.config.client_id,
67
+ redirect_uri: this.config.redirect_uri,
68
+ scope: this.config.scopes.join(','),
69
+ });
70
+ if (state) {
71
+ params.append('state', state);
72
+ }
73
+ return `${this.config.authorization_url}?${params.toString()}`;
74
+ }
75
+ /**
76
+ * 用授权码换取 access_token
77
+ *
78
+ * @param code - 临时授权码,从回调 URL 中获取
79
+ * @returns Token 响应
80
+ */
81
+ async exchangeCodeForToken(code) {
82
+ try {
83
+ const response = await this.httpClient.post(this.config.token_url, {
84
+ grant_type: 'authorization_code',
85
+ client_id: this.config.client_id,
86
+ client_secret: this.config.client_secret,
87
+ code,
88
+ redirect_uri: this.config.redirect_uri,
89
+ });
90
+ return response.data;
91
+ }
92
+ catch (error) {
93
+ throw new Error(`获取 access_token 失败: ${error.message}`);
94
+ }
95
+ }
96
+ /**
97
+ * 刷新 access_token
98
+ *
99
+ * @param refreshToken - 刷新令牌
100
+ * @returns 新的 Token 响应
101
+ */
102
+ async refreshToken(refreshToken) {
103
+ try {
104
+ const response = await this.httpClient.post(this.config.token_url, {
105
+ grant_type: 'refresh_token',
106
+ client_id: this.config.client_id,
107
+ client_secret: this.config.client_secret,
108
+ refresh_token: refreshToken,
109
+ });
110
+ return response.data;
111
+ }
112
+ catch (error) {
113
+ throw new Error(`刷新 token 失败: ${error.message}`);
114
+ }
115
+ }
116
+ /**
117
+ * 验证 token 是否有效
118
+ *
119
+ * @param token - access_token
120
+ * @returns token 是否有效
121
+ */
122
+ async validateToken(token) {
123
+ // 从存储中获取 token 信息
124
+ const keys = (await this.tokenStorage.keys?.()) || [];
125
+ for (const key of keys) {
126
+ const stored = await this.tokenStorage.get(key);
127
+ if (stored && stored.access_token === token) {
128
+ return stored.expiresAt > Date.now();
129
+ }
130
+ }
131
+ return false;
132
+ }
133
+ /**
134
+ * 撤销 token
135
+ *
136
+ * @param token - access_token
137
+ */
138
+ async revokeToken(token) {
139
+ // 从存储中删除
140
+ const keys = (await this.tokenStorage.keys?.()) || [];
141
+ for (const key of keys) {
142
+ const stored = await this.tokenStorage.get(key);
143
+ if (stored && stored.access_token === token) {
144
+ await this.tokenStorage.delete(key);
145
+ break;
146
+ }
147
+ }
148
+ // TODO: 调用金山文档的撤销 token 接口(如果有)
149
+ }
150
+ /**
151
+ * 保存 token 到存储
152
+ *
153
+ * @param key - 缓存键(通常是用户 ID)
154
+ * @param token - Token 响应
155
+ */
156
+ async saveToken(key, token) {
157
+ const expiresAt = Date.now() + token.expires_in * 1000;
158
+ await this.tokenStorage.set(key, {
159
+ ...token,
160
+ expiresAt,
161
+ });
162
+ }
163
+ /**
164
+ * 从存储中获取 token
165
+ *
166
+ * @param key - 缓存键
167
+ * @returns Token,如果不存在或已过期返回 null
168
+ */
169
+ async getToken(key) {
170
+ const token = await this.tokenStorage.get(key);
171
+ if (!token) {
172
+ return null;
173
+ }
174
+ // 检查是否过期(提前 5 分钟视为过期,以便提前刷新)
175
+ const expiresAt = typeof token.expiresAt === 'string' ? parseInt(token.expiresAt, 10) : token.expiresAt;
176
+ if (expiresAt < Date.now() + 5 * 60 * 1000) {
177
+ // token 已过期或即将过期
178
+ if (token.refresh_token) {
179
+ // 尝试刷新 token
180
+ try {
181
+ const newToken = await this.refreshToken(token.refresh_token);
182
+ await this.saveToken(key, newToken);
183
+ return {
184
+ ...newToken,
185
+ expiresAt: Date.now() + newToken.expires_in * 1000,
186
+ };
187
+ }
188
+ catch (error) {
189
+ // 刷新失败,删除存储的 token
190
+ await this.tokenStorage.delete(key);
191
+ return null;
192
+ }
193
+ }
194
+ else {
195
+ // 没有 refresh_token,直接删除
196
+ await this.tokenStorage.delete(key);
197
+ return null;
198
+ }
199
+ }
200
+ return {
201
+ ...token,
202
+ expiresAt,
203
+ };
204
+ }
205
+ /**
206
+ * 从回调 URL 中提取授权码
207
+ *
208
+ * @param callbackUrl - 回调 URL,格式: redirect_uri?code=xxx&state=xxx
209
+ * @returns 授权码
210
+ */
211
+ extractCodeFromCallback(callbackUrl) {
212
+ const url = new URL(callbackUrl);
213
+ const code = url.searchParams.get('code');
214
+ if (!code) {
215
+ throw new Error('回调 URL 中未找到 code 参数');
216
+ }
217
+ return code;
218
+ }
219
+ /**
220
+ * 从回调 URL 中提取 state 参数
221
+ *
222
+ * @param callbackUrl - 回调 URL
223
+ * @returns state 参数
224
+ */
225
+ extractStateFromCallback(callbackUrl) {
226
+ const url = new URL(callbackUrl);
227
+ return url.searchParams.get('state');
228
+ }
229
+ /**
230
+ * 删除指定 key 的 token
231
+ */
232
+ async removeToken(key) {
233
+ await this.tokenStorage.delete(key);
234
+ }
235
+ /**
236
+ * 清空所有 token
237
+ */
238
+ async clearAllTokens() {
239
+ await this.tokenStorage.clear();
240
+ }
241
+ }
242
+ //# sourceMappingURL=wps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wps.js","sourceRoot":"","sources":["../../../src/auth/providers/wps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * OAuth 回调服务器
3
+ *
4
+ * 提供一个简单的 HTTP 服务器来接收 WPS OAuth 回调
5
+ */
6
+ import type { Logger } from '@wps-agent/shared';
7
+ import { WpsAuthProvider } from './providers/wps.js';
8
+ export interface OAuthServerOptions {
9
+ port: number;
10
+ authProvider: WpsAuthProvider;
11
+ logger: Logger;
12
+ onTokenReceived?: (token: string, userId: string) => void;
13
+ }
14
+ /**
15
+ * OAuth 回调服务器
16
+ *
17
+ * 监听 redirect_uri,接收授权码并换取 access_token
18
+ */
19
+ export declare class OAuthCallbackServer {
20
+ private server;
21
+ private authProvider;
22
+ private logger;
23
+ private options;
24
+ constructor(options: OAuthServerOptions);
25
+ /**
26
+ * 启动服务器
27
+ */
28
+ start(): Promise<void>;
29
+ /**
30
+ * 停止服务器
31
+ */
32
+ stop(): Promise<void>;
33
+ /**
34
+ * 处理 HTTP 请求
35
+ */
36
+ private handleRequest;
37
+ /**
38
+ * 处理 OAuth 回调
39
+ */
40
+ private handleCallback;
41
+ /**
42
+ * 发送成功页面
43
+ */
44
+ private sendSuccessPage;
45
+ /**
46
+ * 发送错误页面
47
+ */
48
+ private sendError;
49
+ }
50
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/auth/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,eAAe,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAgD;IAC9D,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,EAAE,kBAAkB;IAMvC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IActB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAarB;;OAEG;YACW,aAAa;IAuB3B;;OAEG;YACW,cAAc;IA4C5B;;OAEG;IACH,OAAO,CAAC,eAAe;IAyEvB;;OAEG;IACH,OAAO,CAAC,SAAS;CA8DlB"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * OAuth 回调服务器
3
+ *
4
+ * 提供一个简单的 HTTP 服务器来接收 WPS OAuth 回调
5
+ */
6
+ import { createServer } from 'http';
7
+ /**
8
+ * OAuth 回调服务器
9
+ *
10
+ * 监听 redirect_uri,接收授权码并换取 access_token
11
+ */
12
+ export class OAuthCallbackServer {
13
+ server = null;
14
+ authProvider;
15
+ logger;
16
+ options;
17
+ constructor(options) {
18
+ this.options = options;
19
+ this.authProvider = options.authProvider;
20
+ this.logger = options.logger;
21
+ }
22
+ /**
23
+ * 启动服务器
24
+ */
25
+ start() {
26
+ return new Promise((resolve) => {
27
+ this.server = createServer((req, res) => {
28
+ this.handleRequest(req, res);
29
+ });
30
+ this.server.listen(this.options.port, () => {
31
+ this.logger.info(`OAuth 回调服务器已启动,监听端口 ${this.options.port}`);
32
+ this.logger.info(`回调地址: http://localhost:${this.options.port}`);
33
+ resolve();
34
+ });
35
+ });
36
+ }
37
+ /**
38
+ * 停止服务器
39
+ */
40
+ stop() {
41
+ return new Promise((resolve) => {
42
+ if (this.server) {
43
+ this.server.close(() => {
44
+ this.logger.info('OAuth 回调服务器已停止');
45
+ resolve();
46
+ });
47
+ }
48
+ else {
49
+ resolve();
50
+ }
51
+ });
52
+ }
53
+ /**
54
+ * 处理 HTTP 请求
55
+ */
56
+ async handleRequest(req, res) {
57
+ const url = new URL(req.url || '', `http://localhost:${this.options.port}`);
58
+ this.logger.debug(`收到请求: ${req.method} ${url.pathname}`);
59
+ // 处理 OAuth 回调
60
+ if (url.pathname === '/callback') {
61
+ await this.handleCallback(url, res);
62
+ return;
63
+ }
64
+ // 健康检查
65
+ if (url.pathname === '/health') {
66
+ res.writeHead(200, { 'Content-Type': 'application/json' });
67
+ res.end(JSON.stringify({ status: 'ok' }));
68
+ return;
69
+ }
70
+ // 404
71
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
72
+ res.end('Not Found');
73
+ }
74
+ /**
75
+ * 处理 OAuth 回调
76
+ */
77
+ async handleCallback(url, res) {
78
+ try {
79
+ // 提取授权码
80
+ const code = url.searchParams.get('code');
81
+ const state = url.searchParams.get('state');
82
+ if (!code) {
83
+ this.logger.error('回调 URL 中未找到 code 参数');
84
+ this.sendError(res, 400, '缺少授权码');
85
+ return;
86
+ }
87
+ this.logger.info(`收到授权码: ${code.substring(0, 10)}...`);
88
+ if (state) {
89
+ this.logger.info(`State: ${state}`);
90
+ }
91
+ // 用授权码换取 access_token
92
+ this.logger.info('正在换取 access_token...');
93
+ const tokenResponse = await this.authProvider.exchangeCodeForToken(code);
94
+ this.logger.info('成功获取 access_token');
95
+ // 保存 token(使用 state 作为 userId,或默认为 'default')
96
+ const userId = state || 'default';
97
+ await this.authProvider.saveToken(userId, tokenResponse);
98
+ this.logger.info(`Token 已保存到缓存 (userId: ${userId})`);
99
+ // 调用回调
100
+ if (this.options.onTokenReceived) {
101
+ this.options.onTokenReceived(tokenResponse.access_token, userId);
102
+ }
103
+ // 返回成功页面
104
+ this.sendSuccessPage(res, tokenResponse.access_token);
105
+ }
106
+ catch (error) {
107
+ const err = error;
108
+ this.logger.error(`处理回调失败: ${err.message}`);
109
+ this.sendError(res, 500, err.message);
110
+ }
111
+ }
112
+ /**
113
+ * 发送成功页面
114
+ */
115
+ sendSuccessPage(res, accessToken) {
116
+ const html = `
117
+ <!DOCTYPE html>
118
+ <html>
119
+ <head>
120
+ <meta charset="UTF-8">
121
+ <title>授权成功</title>
122
+ <style>
123
+ body {
124
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
125
+ display: flex;
126
+ justify-content: center;
127
+ align-items: center;
128
+ height: 100vh;
129
+ margin: 0;
130
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
131
+ }
132
+ .container {
133
+ background: white;
134
+ padding: 40px;
135
+ border-radius: 10px;
136
+ box-shadow: 0 10px 40px rgba(0,0,0,0.1);
137
+ text-align: center;
138
+ max-width: 500px;
139
+ }
140
+ h1 {
141
+ color: #333;
142
+ margin-bottom: 20px;
143
+ }
144
+ .success-icon {
145
+ font-size: 60px;
146
+ color: #4caf50;
147
+ margin-bottom: 20px;
148
+ }
149
+ p {
150
+ color: #666;
151
+ line-height: 1.6;
152
+ }
153
+ .token-info {
154
+ background: #f5f5f5;
155
+ padding: 15px;
156
+ border-radius: 5px;
157
+ margin: 20px 0;
158
+ word-break: break-all;
159
+ font-family: monospace;
160
+ font-size: 12px;
161
+ }
162
+ .note {
163
+ font-size: 14px;
164
+ color: #999;
165
+ margin-top: 20px;
166
+ }
167
+ </style>
168
+ </head>
169
+ <body>
170
+ <div class="container">
171
+ <div class="success-icon">✓</div>
172
+ <h1>授权成功!</h1>
173
+ <p>您已成功授权 WPS Agent 访问您的金山文档。</p>
174
+ <div class="token-info">
175
+ Access Token: ${accessToken.substring(0, 20)}...
176
+ </div>
177
+ <p>现在可以关闭此窗口,返回终端继续操作。</p>
178
+ <p class="note">Token 已自动保存,有效期 2 小时。</p>
179
+ </div>
180
+ </body>
181
+ </html>
182
+ `;
183
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
184
+ res.end(html);
185
+ }
186
+ /**
187
+ * 发送错误页面
188
+ */
189
+ sendError(res, statusCode, message) {
190
+ const html = `
191
+ <!DOCTYPE html>
192
+ <html>
193
+ <head>
194
+ <meta charset="UTF-8">
195
+ <title>授权失败</title>
196
+ <style>
197
+ body {
198
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
199
+ display: flex;
200
+ justify-content: center;
201
+ align-items: center;
202
+ height: 100vh;
203
+ margin: 0;
204
+ background: #f5f5f5;
205
+ }
206
+ .container {
207
+ background: white;
208
+ padding: 40px;
209
+ border-radius: 10px;
210
+ box-shadow: 0 10px 40px rgba(0,0,0,0.1);
211
+ text-align: center;
212
+ max-width: 500px;
213
+ }
214
+ h1 {
215
+ color: #f44336;
216
+ margin-bottom: 20px;
217
+ }
218
+ .error-icon {
219
+ font-size: 60px;
220
+ color: #f44336;
221
+ margin-bottom: 20px;
222
+ }
223
+ p {
224
+ color: #666;
225
+ line-height: 1.6;
226
+ }
227
+ .error-message {
228
+ background: #ffebee;
229
+ padding: 15px;
230
+ border-radius: 5px;
231
+ margin: 20px 0;
232
+ color: #c62828;
233
+ }
234
+ </style>
235
+ </head>
236
+ <body>
237
+ <div class="container">
238
+ <div class="error-icon">✗</div>
239
+ <h1>授权失败</h1>
240
+ <p>授权过程中出现错误:</p>
241
+ <div class="error-message">${message}</div>
242
+ <p>请重试或查看日志了解详情。</p>
243
+ </div>
244
+ </body>
245
+ </html>
246
+ `;
247
+ res.writeHead(statusCode, { 'Content-Type': 'text/html; charset=utf-8' });
248
+ res.end(html);
249
+ }
250
+ }
251
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/auth/server.ts"],"names":[],"mappings":"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"}