@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.
- package/dist/api/client.d.ts +374 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +566 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth/providers/base.d.ts +23 -0
- package/dist/auth/providers/base.d.ts.map +1 -0
- package/dist/auth/providers/base.js +43 -0
- package/dist/auth/providers/base.js.map +1 -0
- package/dist/auth/providers/wps.d.ts +108 -0
- package/dist/auth/providers/wps.d.ts.map +1 -0
- package/dist/auth/providers/wps.js +242 -0
- package/dist/auth/providers/wps.js.map +1 -0
- package/dist/auth/server.d.ts +50 -0
- package/dist/auth/server.d.ts.map +1 -0
- package/dist/auth/server.js +251 -0
- package/dist/auth/server.js.map +1 -0
- package/dist/auth/storage/file.d.ts +70 -0
- package/dist/auth/storage/file.d.ts.map +1 -0
- package/dist/auth/storage/file.js +120 -0
- package/dist/auth/storage/file.js.map +1 -0
- package/dist/auth/storage/interface.d.ts +14 -0
- package/dist/auth/storage/interface.d.ts.map +1 -0
- package/dist/auth/storage/interface.js +5 -0
- package/dist/auth/storage/interface.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/types/api-client.d.ts +229 -0
- package/dist/types/api-client.d.ts.map +1 -0
- package/dist/types/api-client.js +7 -0
- package/dist/types/api-client.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- 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":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAgCtD,MAAM,OAAO,eAAgB,SAAQ,kBAAkB;IAC7C,YAAY,CAAe;IAEnC,YAAY,OAA+B;QACzC,mBAAmB;QACnB,MAAM,aAAa,GAAiB;YAClC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;YACpC,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,MAAM,EAAE,CAAC,uBAAuB,EAAE,yBAAyB,CAAC;YAC5D,oBAAoB;YACpB,iBAAiB,EAAE,oCAAoC;YACvD,SAAS,EAAE,qCAAqC;SACjD,CAAC;QAEF,mDAAmD;QACnD,MAAM,UAAU,GAAG;YACjB,IAAI,EAAE,KAAK,EAAE,GAAW,EAAE,IAA4B,EAAoC,EAAE;gBAC1F,4BAA4B;gBAC5B,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;gBAE3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;oBAChC,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACP,cAAc,EAAE,mCAAmC;qBACpD;oBACD,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE;iBAC1B,CAAC,CAAC;gBAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACxC,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAC;gBAE3D,yBAAyB;gBACzB,OAAO;oBACL,IAAI,EAAE;wBACJ,YAAY,EAAE,MAAM,CAAC,YAAY;wBACjC,aAAa,EAAE,MAAM,CAAC,aAAa;wBACnC,UAAU,EAAE,MAAM,CAAC,UAAU;wBAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;qBAC9B;iBACF,CAAC;YACJ,CAAC;SACF,CAAC;QAEF,KAAK,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QAEjC,eAAe;QACf,IAAI,CAAC,YAAY;YACf,OAAO,CAAC,YAAY;gBACpB,IAAI,gBAAgB,CAAC;oBACnB,QAAQ,EAAE,OAAO,CAAC,gBAAgB;iBACnC,CAAC,CAAC;IACP,CAAC;IAED;;;;;OAKG;IACH,mBAAmB,CAAC,KAAc;QAChC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,aAAa,EAAE,MAAM;YACrB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;YAChC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;YACtC,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;;;;;OAKG;IACH,KAAK,CAAC,oBAAoB,CAAC,IAAY;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;gBACjE,UAAU,EAAE,oBAAoB;gBAChC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;gBAChC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;gBACxC,IAAI;gBACJ,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;aACvC,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,uBAAwB,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;gBACjE,UAAU,EAAE,eAAe;gBAC3B,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS;gBAChC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;gBACxC,aAAa,EAAE,YAAY;aAC5B,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,gBAAiB,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,KAAa;QAC/B,kBAAkB;QAClB,MAAM,IAAI,GAAG,CAAC,MAAO,IAAI,CAAC,YAAiC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QAE5E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,MAAM,IAAI,MAAM,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;gBAC5C,OAAO,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvC,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,SAAS;QACT,MAAM,IAAI,GAAG,CAAC,MAAO,IAAI,CAAC,YAAiC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QAE5E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAChD,IAAI,MAAM,IAAI,MAAM,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;gBAC5C,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACpC,MAAM;YACR,CAAC;QACH,CAAC;QAED,gCAAgC;IAClC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,GAAW,EAAE,KAAoB;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QAEvD,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE;YAC/B,GAAG,KAAK;YACR,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE/C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,6BAA6B;QAC7B,MAAM,SAAS,GACb,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;QAExF,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;YAC3C,iBAAiB;YACjB,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;gBACxB,aAAa;gBACb,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;oBAC9D,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;oBACpC,OAAO;wBACL,GAAG,QAAQ;wBACX,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,UAAU,GAAG,IAAI;qBACnD,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,mBAAmB;oBACnB,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACpC,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,wBAAwB;gBACxB,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACpC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO;YACL,GAAG,KAAK;YACR,SAAS;SACV,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,uBAAuB,CAAC,WAAmB;QACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,wBAAwB,CAAC,WAAmB;QAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,GAAW;QAC3B,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -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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"}
|