@rc-tool/unified-auth-hosted-service 0.2.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/README.md +5 -0
- package/dist/cli/env.d.ts +40 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +350 -0
- package/dist/cli/env.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +145 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -0
- package/dist/hosted-service/applications.d.ts +8 -0
- package/dist/hosted-service/applications.d.ts.map +1 -0
- package/dist/hosted-service/applications.js +33 -0
- package/dist/hosted-service/applications.js.map +1 -0
- package/dist/hosted-service/constants.d.ts +6 -0
- package/dist/hosted-service/constants.d.ts.map +1 -0
- package/dist/hosted-service/constants.js +6 -0
- package/dist/hosted-service/constants.js.map +1 -0
- package/dist/hosted-service/cookies.d.ts +17 -0
- package/dist/hosted-service/cookies.d.ts.map +1 -0
- package/dist/hosted-service/cookies.js +56 -0
- package/dist/hosted-service/cookies.js.map +1 -0
- package/dist/hosted-service/crypto.d.ts +3 -0
- package/dist/hosted-service/crypto.d.ts.map +1 -0
- package/dist/hosted-service/crypto.js +39 -0
- package/dist/hosted-service/crypto.js.map +1 -0
- package/dist/hosted-service/http.d.ts +4 -0
- package/dist/hosted-service/http.d.ts.map +1 -0
- package/dist/hosted-service/http.js +27 -0
- package/dist/hosted-service/http.js.map +1 -0
- package/dist/hosted-service/login-page/components.d.ts +7 -0
- package/dist/hosted-service/login-page/components.d.ts.map +1 -0
- package/dist/hosted-service/login-page/components.js +40 -0
- package/dist/hosted-service/login-page/components.js.map +1 -0
- package/dist/hosted-service/login-page/document.d.ts +5 -0
- package/dist/hosted-service/login-page/document.d.ts.map +1 -0
- package/dist/hosted-service/login-page/document.js +19 -0
- package/dist/hosted-service/login-page/document.js.map +1 -0
- package/dist/hosted-service/login-page/escape.d.ts +2 -0
- package/dist/hosted-service/login-page/escape.d.ts.map +1 -0
- package/dist/hosted-service/login-page/escape.js +9 -0
- package/dist/hosted-service/login-page/escape.js.map +1 -0
- package/dist/hosted-service/login-page/icons.d.ts +5 -0
- package/dist/hosted-service/login-page/icons.d.ts.map +1 -0
- package/dist/hosted-service/login-page/icons.js +20 -0
- package/dist/hosted-service/login-page/icons.js.map +1 -0
- package/dist/hosted-service/login-page/index.d.ts +3 -0
- package/dist/hosted-service/login-page/index.d.ts.map +1 -0
- package/dist/hosted-service/login-page/index.js +23 -0
- package/dist/hosted-service/login-page/index.js.map +1 -0
- package/dist/hosted-service/login-page/links.d.ts +3 -0
- package/dist/hosted-service/login-page/links.d.ts.map +1 -0
- package/dist/hosted-service/login-page/links.js +50 -0
- package/dist/hosted-service/login-page/links.js.map +1 -0
- package/dist/hosted-service/login-page/styles.d.ts +2 -0
- package/dist/hosted-service/login-page/styles.d.ts.map +1 -0
- package/dist/hosted-service/login-page/styles.js +35 -0
- package/dist/hosted-service/login-page/styles.js.map +1 -0
- package/dist/hosted-service/login-page/types.d.ts +26 -0
- package/dist/hosted-service/login-page/types.d.ts.map +1 -0
- package/dist/hosted-service/login-page/types.js +2 -0
- package/dist/hosted-service/login-page/types.js.map +1 -0
- package/dist/hosted-service/oauth.d.ts +11 -0
- package/dist/hosted-service/oauth.d.ts.map +1 -0
- package/dist/hosted-service/oauth.js +37 -0
- package/dist/hosted-service/oauth.js.map +1 -0
- package/dist/hosted-service/providers/feishu.d.ts +4 -0
- package/dist/hosted-service/providers/feishu.d.ts.map +1 -0
- package/dist/hosted-service/providers/feishu.js +72 -0
- package/dist/hosted-service/providers/feishu.js.map +1 -0
- package/dist/hosted-service/providers/github.d.ts +4 -0
- package/dist/hosted-service/providers/github.d.ts.map +1 -0
- package/dist/hosted-service/providers/github.js +73 -0
- package/dist/hosted-service/providers/github.js.map +1 -0
- package/dist/hosted-service/providers/google.d.ts +4 -0
- package/dist/hosted-service/providers/google.d.ts.map +1 -0
- package/dist/hosted-service/providers/google.js +54 -0
- package/dist/hosted-service/providers/google.js.map +1 -0
- package/dist/hosted-service/routes.d.ts +12 -0
- package/dist/hosted-service/routes.d.ts.map +1 -0
- package/dist/hosted-service/routes.js +61 -0
- package/dist/hosted-service/routes.js.map +1 -0
- package/dist/hosted-service/service.d.ts +16 -0
- package/dist/hosted-service/service.d.ts.map +1 -0
- package/dist/hosted-service/service.js +205 -0
- package/dist/hosted-service/service.js.map +1 -0
- package/dist/hosted-service/session.d.ts +11 -0
- package/dist/hosted-service/session.d.ts.map +1 -0
- package/dist/hosted-service/session.js +52 -0
- package/dist/hosted-service/session.js.map +1 -0
- package/dist/hosted-service/store/file.d.ts +6 -0
- package/dist/hosted-service/store/file.d.ts.map +1 -0
- package/dist/hosted-service/store/file.js +62 -0
- package/dist/hosted-service/store/file.js.map +1 -0
- package/dist/hosted-service/store/index.d.ts +6 -0
- package/dist/hosted-service/store/index.d.ts.map +1 -0
- package/dist/hosted-service/store/index.js +3 -0
- package/dist/hosted-service/store/index.js.map +1 -0
- package/dist/hosted-service/store/memory.d.ts +6 -0
- package/dist/hosted-service/store/memory.d.ts.map +1 -0
- package/dist/hosted-service/store/memory.js +19 -0
- package/dist/hosted-service/store/memory.js.map +1 -0
- package/dist/hosted-service/store/state.d.ts +9 -0
- package/dist/hosted-service/store/state.d.ts.map +1 -0
- package/dist/hosted-service/store/state.js +156 -0
- package/dist/hosted-service/store/state.js.map +1 -0
- package/dist/hosted-service/store/types.d.ts +56 -0
- package/dist/hosted-service/store/types.d.ts.map +1 -0
- package/dist/hosted-service/store/types.js +2 -0
- package/dist/hosted-service/store/types.js.map +1 -0
- package/dist/hosted-service/types.d.ts +48 -0
- package/dist/hosted-service/types.d.ts.map +1 -0
- package/dist/hosted-service/types.js +2 -0
- package/dist/hosted-service/types.js.map +1 -0
- package/dist/hosted-service-cli.d.ts +2 -0
- package/dist/hosted-service-cli.d.ts.map +1 -0
- package/dist/hosted-service-cli.js +89 -0
- package/dist/hosted-service-cli.js.map +1 -0
- package/dist/hosted-service-node.d.ts +7 -0
- package/dist/hosted-service-node.d.ts.map +1 -0
- package/dist/hosted-service-node.js +35 -0
- package/dist/hosted-service-node.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { AUTH_SERVICE_STATE_COOKIE, STATE_MAX_AGE_SECONDS } from "./constants.js";
|
|
3
|
+
import { getCookie, serializeCookie, shouldUseSecureCookie } from "./cookies.js";
|
|
4
|
+
import { createSignedToken, parseSignedToken } from "./crypto.js";
|
|
5
|
+
export function createOAuthState(app, redirectURI) {
|
|
6
|
+
const state = randomBytes(24).toString("base64url");
|
|
7
|
+
const payload = {
|
|
8
|
+
clientId: app.clientId,
|
|
9
|
+
exp: Math.floor(Date.now() / 1000) + STATE_MAX_AGE_SECONDS,
|
|
10
|
+
redirectURI,
|
|
11
|
+
state,
|
|
12
|
+
};
|
|
13
|
+
return { payload, state };
|
|
14
|
+
}
|
|
15
|
+
export function createOAuthStateCookie(request, options, payload) {
|
|
16
|
+
return serializeCookie({
|
|
17
|
+
domain: options.cookieDomain,
|
|
18
|
+
maxAge: STATE_MAX_AGE_SECONDS,
|
|
19
|
+
name: AUTH_SERVICE_STATE_COOKIE,
|
|
20
|
+
secure: shouldUseSecureCookie(request),
|
|
21
|
+
value: createSignedToken(payload, options.sessionSecret),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export function readOAuthCallbackState(request, options) {
|
|
25
|
+
const url = new URL(request.url);
|
|
26
|
+
const code = url.searchParams.get("code");
|
|
27
|
+
const state = url.searchParams.get("state");
|
|
28
|
+
const savedState = parseSignedToken(getCookie(request, AUTH_SERVICE_STATE_COOKIE), options.sessionSecret);
|
|
29
|
+
if (!code || !state || !savedState || savedState.state !== state || isExpired(savedState)) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return { code, savedState };
|
|
33
|
+
}
|
|
34
|
+
function isExpired(savedState) {
|
|
35
|
+
return savedState.exp < Math.floor(Date.now() / 1000);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/hosted-service/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGlE,MAAM,UAAU,gBAAgB,CAAC,GAA0B,EAAE,WAAmB;IAC9E,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,OAAO,GAAiB;QAC5B,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,qBAAqB;QAC1D,WAAW;QACX,KAAK;KACN,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAAgB,EAChB,OAAiC,EACjC,OAAqB;IAErB,OAAO,eAAe,CAAC;QACrB,MAAM,EAAE,OAAO,CAAC,YAAY;QAC5B,MAAM,EAAE,qBAAqB;QAC7B,IAAI,EAAE,yBAAyB;QAC/B,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC;QACtC,KAAK,EAAE,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAAgB,EAAE,OAAiC;IACxF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,gBAAgB,CACjC,SAAS,CAAC,OAAO,EAAE,yBAAyB,CAAC,EAC7C,OAAO,CAAC,aAAa,CACtB,CAAC;IAEF,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,KAAK,KAAK,KAAK,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1F,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,SAAS,CAAC,UAAwB;IACzC,OAAO,UAAU,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AuthUser } from "@rc-tool/unified-auth-sdk/service-client";
|
|
2
|
+
import type { HostedAuthServiceOptions } from "../types.js";
|
|
3
|
+
export declare function createUserFromFeishuCode(options: HostedAuthServiceOptions, code: string): Promise<AuthUser>;
|
|
4
|
+
//# sourceMappingURL=feishu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feishu.d.ts","sourceRoot":"","sources":["../../../src/hosted-service/providers/feishu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAwD5D,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,CAAC,CAmCnB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
async function getFeishuAppAccessToken(appId, appSecret) {
|
|
2
|
+
const response = await fetch("https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal", {
|
|
3
|
+
body: JSON.stringify({
|
|
4
|
+
app_id: appId,
|
|
5
|
+
app_secret: appSecret,
|
|
6
|
+
}),
|
|
7
|
+
headers: { "content-type": "application/json" },
|
|
8
|
+
method: "POST",
|
|
9
|
+
});
|
|
10
|
+
const payload = (await response.json());
|
|
11
|
+
if (!response.ok || payload.code !== 0 || !payload.app_access_token) {
|
|
12
|
+
throw new Error(payload.msg || "获取飞书 app_access_token 失败");
|
|
13
|
+
}
|
|
14
|
+
return payload.app_access_token;
|
|
15
|
+
}
|
|
16
|
+
export async function createUserFromFeishuCode(options, code) {
|
|
17
|
+
const appId = options.feishu?.appId;
|
|
18
|
+
const appSecret = options.feishu?.appSecret;
|
|
19
|
+
if (!appId || !appSecret) {
|
|
20
|
+
throw new Error("飞书登录未配置");
|
|
21
|
+
}
|
|
22
|
+
const appAccessToken = await getFeishuAppAccessToken(appId, appSecret);
|
|
23
|
+
const tokenPayload = await exchangeFeishuCode(code, appAccessToken);
|
|
24
|
+
const userInfo = await getFeishuUserInfo(tokenPayload.data.access_token);
|
|
25
|
+
const openId = userInfo?.open_id || tokenPayload.data.open_id;
|
|
26
|
+
if (!openId) {
|
|
27
|
+
throw new Error("飞书返回的用户信息缺少 open_id");
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
avatarUrl: userInfo?.avatar_big ||
|
|
31
|
+
userInfo?.avatar_middle ||
|
|
32
|
+
userInfo?.avatar_url ||
|
|
33
|
+
tokenPayload.data.avatar_url ||
|
|
34
|
+
null,
|
|
35
|
+
email: userInfo?.email || tokenPayload.data.email || null,
|
|
36
|
+
id: openId,
|
|
37
|
+
metadata: {
|
|
38
|
+
enName: userInfo?.en_name || tokenPayload.data.en_name,
|
|
39
|
+
feishuOpenId: openId,
|
|
40
|
+
feishuUnionId: userInfo?.union_id || tokenPayload.data.union_id,
|
|
41
|
+
feishuUserId: userInfo?.user_id || tokenPayload.data.user_id,
|
|
42
|
+
provider: "feishu",
|
|
43
|
+
},
|
|
44
|
+
name: userInfo?.name || tokenPayload.data.name || "飞书用户",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function exchangeFeishuCode(code, appAccessToken) {
|
|
48
|
+
const response = await fetch("https://open.feishu.cn/open-apis/authen/v1/access_token", {
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
code,
|
|
51
|
+
grant_type: "authorization_code",
|
|
52
|
+
}),
|
|
53
|
+
headers: {
|
|
54
|
+
authorization: `Bearer ${appAccessToken}`,
|
|
55
|
+
"content-type": "application/json",
|
|
56
|
+
},
|
|
57
|
+
method: "POST",
|
|
58
|
+
});
|
|
59
|
+
const payload = (await response.json());
|
|
60
|
+
if (!response.ok || payload.code !== 0 || !payload.data?.access_token) {
|
|
61
|
+
throw new Error(payload.msg || payload.message || "飞书授权码换取 user_access_token 失败");
|
|
62
|
+
}
|
|
63
|
+
return { data: payload.data };
|
|
64
|
+
}
|
|
65
|
+
async function getFeishuUserInfo(accessToken) {
|
|
66
|
+
const response = await fetch("https://open.feishu.cn/open-apis/authen/v1/user_info", {
|
|
67
|
+
headers: { authorization: `Bearer ${accessToken}` },
|
|
68
|
+
});
|
|
69
|
+
const payload = (await response.json());
|
|
70
|
+
return payload.code === 0 ? payload.data : null;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=feishu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feishu.js","sourceRoot":"","sources":["../../../src/hosted-service/providers/feishu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AuthUser } from "@rc-tool/unified-auth-sdk/service-client";
|
|
2
|
+
import type { HostedAuthServiceOptions } from "../types.js";
|
|
3
|
+
export declare function createUserFromGitHubCode(options: HostedAuthServiceOptions, code: string, redirectURI: string): Promise<AuthUser>;
|
|
4
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../src/hosted-service/providers/github.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAuB5D,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,QAAQ,CAAC,CAqBnB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export async function createUserFromGitHubCode(options, code, redirectURI) {
|
|
2
|
+
const accessToken = await exchangeGitHubCode(options, code, redirectURI);
|
|
3
|
+
const apiHeaders = createGitHubApiHeaders(accessToken);
|
|
4
|
+
const userInfo = await getGitHubUserInfo(apiHeaders);
|
|
5
|
+
const primaryEmail = userInfo.email ? undefined : await getGitHubPrimaryEmail(apiHeaders);
|
|
6
|
+
const email = userInfo.email ?? primaryEmail?.email ?? null;
|
|
7
|
+
return {
|
|
8
|
+
avatarUrl: userInfo.avatar_url ?? null,
|
|
9
|
+
email,
|
|
10
|
+
id: `github:${userInfo.id}`,
|
|
11
|
+
metadata: {
|
|
12
|
+
emailVerified: primaryEmail?.verified,
|
|
13
|
+
githubDisplayName: userInfo.name,
|
|
14
|
+
githubId: userInfo.id,
|
|
15
|
+
githubLogin: userInfo.login,
|
|
16
|
+
githubUrl: userInfo.html_url,
|
|
17
|
+
provider: "github",
|
|
18
|
+
},
|
|
19
|
+
name: userInfo.login || userInfo.name || email || "GitHub 用户",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async function exchangeGitHubCode(options, code, redirectURI) {
|
|
23
|
+
const clientId = options.github?.clientId;
|
|
24
|
+
const clientSecret = options.github?.clientSecret;
|
|
25
|
+
if (!clientId || !clientSecret) {
|
|
26
|
+
throw new Error("GitHub 登录未配置");
|
|
27
|
+
}
|
|
28
|
+
const response = await fetch("https://github.com/login/oauth/access_token", {
|
|
29
|
+
body: new URLSearchParams({
|
|
30
|
+
client_id: clientId,
|
|
31
|
+
client_secret: clientSecret,
|
|
32
|
+
code,
|
|
33
|
+
redirect_uri: redirectURI,
|
|
34
|
+
}),
|
|
35
|
+
headers: {
|
|
36
|
+
accept: "application/json",
|
|
37
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
38
|
+
},
|
|
39
|
+
method: "POST",
|
|
40
|
+
});
|
|
41
|
+
const payload = (await response.json());
|
|
42
|
+
if (!response.ok || !payload.access_token) {
|
|
43
|
+
throw new Error(payload.error_description || payload.error || "GitHub 授权码换取 access_token 失败");
|
|
44
|
+
}
|
|
45
|
+
return payload.access_token;
|
|
46
|
+
}
|
|
47
|
+
function createGitHubApiHeaders(accessToken) {
|
|
48
|
+
return {
|
|
49
|
+
accept: "application/vnd.github+json",
|
|
50
|
+
authorization: `Bearer ${accessToken}`,
|
|
51
|
+
"user-agent": "unified-auth-sdk",
|
|
52
|
+
"x-github-api-version": "2022-11-28",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async function getGitHubUserInfo(headers) {
|
|
56
|
+
const response = await fetch("https://api.github.com/user", { headers });
|
|
57
|
+
const userInfo = (await response.json());
|
|
58
|
+
if (!response.ok || !userInfo.id) {
|
|
59
|
+
throw new Error("GitHub 返回的用户信息缺少 id");
|
|
60
|
+
}
|
|
61
|
+
return userInfo;
|
|
62
|
+
}
|
|
63
|
+
async function getGitHubPrimaryEmail(headers) {
|
|
64
|
+
const response = await fetch("https://api.github.com/user/emails", { headers });
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
const emails = (await response.json());
|
|
69
|
+
return (emails.find((item) => item.primary && item.verified) ??
|
|
70
|
+
emails.find((item) => item.verified) ??
|
|
71
|
+
emails.find((item) => item.email));
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/hosted-service/providers/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AuthUser } from "@rc-tool/unified-auth-sdk/service-client";
|
|
2
|
+
import type { HostedAuthServiceOptions } from "../types.js";
|
|
3
|
+
export declare function createUserFromGoogleCode(options: HostedAuthServiceOptions, code: string, redirectURI: string): Promise<AuthUser>;
|
|
4
|
+
//# sourceMappingURL=google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/hosted-service/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAkB5D,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,QAAQ,CAAC,CAqBnB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export async function createUserFromGoogleCode(options, code, redirectURI) {
|
|
2
|
+
const tokenPayload = await exchangeGoogleCode(options, code, redirectURI);
|
|
3
|
+
const userInfo = await getGoogleUserInfo(tokenPayload.access_token);
|
|
4
|
+
if (!userInfo.sub) {
|
|
5
|
+
throw new Error("Google 返回的用户信息缺少 sub");
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
avatarUrl: userInfo.picture ?? null,
|
|
9
|
+
email: userInfo.email ?? null,
|
|
10
|
+
id: userInfo.sub,
|
|
11
|
+
metadata: {
|
|
12
|
+
emailVerified: userInfo.email_verified,
|
|
13
|
+
familyName: userInfo.family_name,
|
|
14
|
+
givenName: userInfo.given_name,
|
|
15
|
+
googleSub: userInfo.sub,
|
|
16
|
+
provider: "google",
|
|
17
|
+
},
|
|
18
|
+
name: userInfo.name || userInfo.email || "Google 用户",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function exchangeGoogleCode(options, code, redirectURI) {
|
|
22
|
+
const clientId = options.google?.clientId;
|
|
23
|
+
const clientSecret = options.google?.clientSecret;
|
|
24
|
+
if (!clientId || !clientSecret) {
|
|
25
|
+
throw new Error("Google 登录未配置");
|
|
26
|
+
}
|
|
27
|
+
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
28
|
+
body: new URLSearchParams({
|
|
29
|
+
client_id: clientId,
|
|
30
|
+
client_secret: clientSecret,
|
|
31
|
+
code,
|
|
32
|
+
grant_type: "authorization_code",
|
|
33
|
+
redirect_uri: redirectURI,
|
|
34
|
+
}),
|
|
35
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
36
|
+
method: "POST",
|
|
37
|
+
});
|
|
38
|
+
const payload = (await response.json());
|
|
39
|
+
if (!response.ok || !payload.access_token) {
|
|
40
|
+
throw new Error(payload.error_description || payload.error || "Google 授权码换取 access_token 失败");
|
|
41
|
+
}
|
|
42
|
+
return { access_token: payload.access_token };
|
|
43
|
+
}
|
|
44
|
+
async function getGoogleUserInfo(accessToken) {
|
|
45
|
+
const response = await fetch("https://openidconnect.googleapis.com/v1/userinfo", {
|
|
46
|
+
headers: { authorization: `Bearer ${accessToken}` },
|
|
47
|
+
});
|
|
48
|
+
const userInfo = (await response.json());
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new Error("Google 用户信息获取失败");
|
|
51
|
+
}
|
|
52
|
+
return userInfo;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/hosted-service/providers/google.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAiC,EACjC,IAAY,EACZ,WAAmB;IAEnB,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAEpE,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO;QACL,SAAS,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI;QACnC,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,IAAI;QAC7B,EAAE,EAAE,QAAQ,CAAC,GAAG;QAChB,QAAQ,EAAE;YACR,aAAa,EAAE,QAAQ,CAAC,cAAc;YACtC,UAAU,EAAE,QAAQ,CAAC,WAAW;YAChC,SAAS,EAAE,QAAQ,CAAC,UAAU;YAC9B,SAAS,EAAE,QAAQ,CAAC,GAAG;YACvB,QAAQ,EAAE,QAAQ;SACnB;QACD,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,KAAK,IAAI,WAAW;KACrD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,OAAiC,EAAE,IAAY,EAAE,WAAmB;IACpG,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1C,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;IAElD,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,qCAAqC,EAAE;QAClE,IAAI,EAAE,IAAI,eAAe,CAAC;YACxB,SAAS,EAAE,QAAQ;YACnB,aAAa,EAAE,YAAY;YAC3B,IAAI;YACJ,UAAU,EAAE,oBAAoB;YAChC,YAAY,EAAE,WAAW;SAC1B,CAAC;QACF,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,MAAM,EAAE,MAAM;KACf,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;IAE/D,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,iBAAiB,IAAI,OAAO,CAAC,KAAK,IAAI,8BAA8B,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IAClD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kDAAkD,EAAE;QAC/E,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE;KACpD,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2B,CAAC;IAEnE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createHostedAuthService } from "./service.js";
|
|
2
|
+
import type { HostedAuthServiceOptions } from "./types.js";
|
|
3
|
+
export type HostedAuthRouteHandler = (request: Request) => Promise<Response>;
|
|
4
|
+
export interface HostedAuthRouteHandlers {
|
|
5
|
+
GET: HostedAuthRouteHandler;
|
|
6
|
+
POST: HostedAuthRouteHandler;
|
|
7
|
+
handle: HostedAuthRouteHandler;
|
|
8
|
+
service: ReturnType<typeof createHostedAuthService>;
|
|
9
|
+
}
|
|
10
|
+
export declare function createHostedAuthRouteHandlers(options: HostedAuthServiceOptions): HostedAuthRouteHandlers;
|
|
11
|
+
export declare function handleHostedAuthRequest(service: ReturnType<typeof createHostedAuthService>, request: Request): Promise<Response>;
|
|
12
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/hosted-service/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE7E,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,sBAAsB,CAAC;IAC5B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;CACrD;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB,CAkBxG;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,EACnD,OAAO,EAAE,OAAO,qBA0CjB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createHostedAuthService } from "./service.js";
|
|
2
|
+
export function createHostedAuthRouteHandlers(options) {
|
|
3
|
+
const service = createHostedAuthService(options);
|
|
4
|
+
const handle = async (request) => {
|
|
5
|
+
try {
|
|
6
|
+
return await handleHostedAuthRequest(service, request);
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
return new Response(error instanceof Error ? error.message : "Auth service error", {
|
|
10
|
+
status: 500,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
GET: handle,
|
|
16
|
+
POST: handle,
|
|
17
|
+
handle,
|
|
18
|
+
service,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function handleHostedAuthRequest(service, request) {
|
|
22
|
+
const path = new URL(request.url).pathname;
|
|
23
|
+
if (path === "/login") {
|
|
24
|
+
return service.handleLogin(request);
|
|
25
|
+
}
|
|
26
|
+
if (path === "/logout") {
|
|
27
|
+
return service.handleLogout(request);
|
|
28
|
+
}
|
|
29
|
+
if (path === "/api/auth/context") {
|
|
30
|
+
return service.handleContext(request);
|
|
31
|
+
}
|
|
32
|
+
if (path === "/api/auth/dev-login") {
|
|
33
|
+
return service.handleDevLogin(request);
|
|
34
|
+
}
|
|
35
|
+
if (path === "/api/auth/feishu/callback") {
|
|
36
|
+
return service.handleFeishuCallback(request);
|
|
37
|
+
}
|
|
38
|
+
if (path === "/api/auth/feishu/start") {
|
|
39
|
+
return service.handleFeishuStart(request);
|
|
40
|
+
}
|
|
41
|
+
if (path === "/api/auth/google/callback") {
|
|
42
|
+
return service.handleGoogleCallback(request);
|
|
43
|
+
}
|
|
44
|
+
if (path === "/api/auth/google/start") {
|
|
45
|
+
return service.handleGoogleStart(request);
|
|
46
|
+
}
|
|
47
|
+
if (path === "/api/auth/github/callback") {
|
|
48
|
+
return service.handleGitHubCallback(request);
|
|
49
|
+
}
|
|
50
|
+
if (path === "/api/auth/github/start") {
|
|
51
|
+
return service.handleGitHubStart(request);
|
|
52
|
+
}
|
|
53
|
+
if (path === "/api/auth/me" || path === "/api/auth/user") {
|
|
54
|
+
return service.handleUser(request);
|
|
55
|
+
}
|
|
56
|
+
if (path === "/api/auth/session") {
|
|
57
|
+
return service.handleSession(request);
|
|
58
|
+
}
|
|
59
|
+
return new Response("Not found", { status: 404 });
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/hosted-service/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAYvD,MAAM,UAAU,6BAA6B,CAAC,OAAiC;IAC7E,MAAM,OAAO,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,KAAK,EAAE,OAAgB,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,OAAO,MAAM,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,QAAQ,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,EAAE;gBACjF,MAAM,EAAE,GAAG;aACZ,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,MAAM;QACX,IAAI,EAAE,MAAM;QACZ,MAAM;QACN,OAAO;KACR,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAmD,EACnD,OAAgB;IAEhB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAE3C,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,IAAI,KAAK,qBAAqB,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,IAAI,KAAK,2BAA2B,EAAE,CAAC;QACzC,OAAO,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,IAAI,KAAK,wBAAwB,EAAE,CAAC;QACtC,OAAO,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,KAAK,2BAA2B,EAAE,CAAC;QACzC,OAAO,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,IAAI,KAAK,wBAAwB,EAAE,CAAC;QACtC,OAAO,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,KAAK,2BAA2B,EAAE,CAAC;QACzC,OAAO,OAAO,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,IAAI,KAAK,wBAAwB,EAAE,CAAC;QACtC,OAAO,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACzD,OAAO,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HostedAuthServiceOptions } from "./types.js";
|
|
2
|
+
export declare function createHostedAuthService(options: HostedAuthServiceOptions): {
|
|
3
|
+
handleContext(request: Request): Promise<Response>;
|
|
4
|
+
handleDevLogin(request: Request): Promise<Response>;
|
|
5
|
+
handleFeishuCallback(request: Request): Promise<Response>;
|
|
6
|
+
handleFeishuStart(request: Request): Promise<Response>;
|
|
7
|
+
handleGitHubCallback(request: Request): Promise<Response>;
|
|
8
|
+
handleGitHubStart(request: Request): Promise<Response>;
|
|
9
|
+
handleGoogleCallback(request: Request): Promise<Response>;
|
|
10
|
+
handleGoogleStart(request: Request): Promise<Response>;
|
|
11
|
+
handleLogin(request: Request): Promise<Response>;
|
|
12
|
+
handleLogout(request: Request): Promise<Response>;
|
|
13
|
+
handleSession(request: Request): Promise<Response>;
|
|
14
|
+
handleUser(request: Request): Promise<Response>;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/hosted-service/service.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAyB,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAIlF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB;2BAiExC,OAAO;4BAGN,OAAO;kCAGD,OAAO;+BAGV,OAAO;kCAGJ,OAAO;+BAIV,OAAO;kCAGJ,OAAO;+BAIV,OAAO;yBAGb,OAAO;0BAGN,OAAO;2BASN,OAAO;wBAKV,OAAO;EAkEpC"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { createProviderStartUrl, getApplication, getClientId, getRedirectURI, isRedirectAllowed, normalizeBaseURL } from "./applications.js";
|
|
2
|
+
import { AUTH_SERVICE_SESSION_COOKIE, AUTH_SERVICE_STATE_COOKIE } from "./constants.js";
|
|
3
|
+
import { appendCookie, clearCookie, createSessionCookie } from "./cookies.js";
|
|
4
|
+
import { html, json, redirect } from "./http.js";
|
|
5
|
+
import { renderLoginPage } from "./login-page/index.js";
|
|
6
|
+
import { createOAuthState, createOAuthStateCookie, readOAuthCallbackState } from "./oauth.js";
|
|
7
|
+
import { createUserFromFeishuCode } from "./providers/feishu.js";
|
|
8
|
+
import { createUserFromGitHubCode } from "./providers/github.js";
|
|
9
|
+
import { createUserFromGoogleCode } from "./providers/google.js";
|
|
10
|
+
import { createSessionExpiresAt, createSessionPayload, deleteRequestSession, getStoredSession, toAuthContext, toAuthSession, } from "./session.js";
|
|
11
|
+
import { createMemoryAuthStore } from "./store/index.js";
|
|
12
|
+
export function createHostedAuthService(options) {
|
|
13
|
+
const authBaseURL = normalizeBaseURL(options.authBaseURL);
|
|
14
|
+
const allowDevLogin = options.allowDevLogin ?? false;
|
|
15
|
+
const store = options.store ?? createMemoryAuthStore();
|
|
16
|
+
async function setSessionAndRedirect(request, provider, providerUser, clientId, redirectURI) {
|
|
17
|
+
const user = await store.upsertOAuthUser(provider, providerUser);
|
|
18
|
+
const session = await store.createSession({
|
|
19
|
+
clientId,
|
|
20
|
+
expiresAt: createSessionExpiresAt(),
|
|
21
|
+
provider,
|
|
22
|
+
providerAccountId: providerUser.id,
|
|
23
|
+
userId: user.id,
|
|
24
|
+
});
|
|
25
|
+
const headers = new Headers();
|
|
26
|
+
appendCookie(headers, createSessionCookie(request, options, createSessionPayload(session)));
|
|
27
|
+
appendCookie(headers, clearCookie(request, options, AUTH_SERVICE_STATE_COOKIE));
|
|
28
|
+
return redirect(redirectURI, headers);
|
|
29
|
+
}
|
|
30
|
+
async function handleProviderCallback(request, provider, createUser) {
|
|
31
|
+
const stateData = readOAuthCallbackState(request, options);
|
|
32
|
+
if (!stateData) {
|
|
33
|
+
return redirect(`${authBaseURL}/login?error=${encodeURIComponent("登录状态校验失败,请重新发起登录。")}`);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const user = await createUser(stateData.code, getCallbackURL(provider));
|
|
37
|
+
return setSessionAndRedirect(request, provider, user, stateData.savedState.clientId, stateData.savedState.redirectURI);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return redirect(createCallbackErrorUrl(provider, error, stateData.savedState.clientId, stateData.savedState.redirectURI));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function handleProviderStart(request, provider) {
|
|
44
|
+
const providerClientId = getProviderClientId(provider);
|
|
45
|
+
const clientId = getClientId(request, options);
|
|
46
|
+
const app = getApplication(options, clientId);
|
|
47
|
+
const redirectURI = getRedirectURI(request, app);
|
|
48
|
+
if (!providerClientId) {
|
|
49
|
+
return redirect(`${authBaseURL}/login?client_id=${encodeURIComponent(clientId)}&error=${encodeURIComponent(getProviderDisabledMessage(provider))}`);
|
|
50
|
+
}
|
|
51
|
+
if (!isRedirectAllowed(redirectURI, app)) {
|
|
52
|
+
return json({ error: "redirect_uri 不在应用白名单中" }, { status: 400 });
|
|
53
|
+
}
|
|
54
|
+
return redirectToProvider(request, app, redirectURI, provider, providerClientId);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
async handleContext(request) {
|
|
58
|
+
return json(toAuthContext(await getStoredSession(request, options, store)));
|
|
59
|
+
},
|
|
60
|
+
async handleDevLogin(request) {
|
|
61
|
+
return handleDevLogin(request, options, allowDevLogin, setSessionAndRedirect);
|
|
62
|
+
},
|
|
63
|
+
async handleFeishuCallback(request) {
|
|
64
|
+
return handleProviderCallback(request, "feishu", (code) => createUserFromFeishuCode(options, code));
|
|
65
|
+
},
|
|
66
|
+
async handleFeishuStart(request) {
|
|
67
|
+
return handleProviderStart(request, "feishu");
|
|
68
|
+
},
|
|
69
|
+
async handleGitHubCallback(request) {
|
|
70
|
+
return handleProviderCallback(request, "github", (code, callbackURL) => createUserFromGitHubCode(options, code, callbackURL));
|
|
71
|
+
},
|
|
72
|
+
async handleGitHubStart(request) {
|
|
73
|
+
return handleProviderStart(request, "github");
|
|
74
|
+
},
|
|
75
|
+
async handleGoogleCallback(request) {
|
|
76
|
+
return handleProviderCallback(request, "google", (code, callbackURL) => createUserFromGoogleCode(options, code, callbackURL));
|
|
77
|
+
},
|
|
78
|
+
async handleGoogleStart(request) {
|
|
79
|
+
return handleProviderStart(request, "google");
|
|
80
|
+
},
|
|
81
|
+
async handleLogin(request) {
|
|
82
|
+
return handleLogin(request, options, authBaseURL, allowDevLogin);
|
|
83
|
+
},
|
|
84
|
+
async handleLogout(request) {
|
|
85
|
+
const url = new URL(request.url);
|
|
86
|
+
const headers = new Headers();
|
|
87
|
+
await deleteRequestSession(request, options, store);
|
|
88
|
+
appendCookie(headers, clearCookie(request, options, options.cookieName ?? AUTH_SERVICE_SESSION_COOKIE));
|
|
89
|
+
return redirect(url.searchParams.get("redirect_uri") ?? "/", headers);
|
|
90
|
+
},
|
|
91
|
+
async handleSession(request) {
|
|
92
|
+
const stored = await getStoredSession(request, options, store);
|
|
93
|
+
return json(stored ? toAuthSession(stored.session) : null);
|
|
94
|
+
},
|
|
95
|
+
async handleUser(request) {
|
|
96
|
+
return json((await getStoredSession(request, options, store))?.user ?? null);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
function getCallbackURL(provider) {
|
|
100
|
+
return options[provider]?.redirectURI ?? `${authBaseURL}/api/auth/${provider}/callback`;
|
|
101
|
+
}
|
|
102
|
+
function getProviderClientId(provider) {
|
|
103
|
+
return provider === "feishu" ? options.feishu?.appId : options[provider]?.clientId;
|
|
104
|
+
}
|
|
105
|
+
function redirectToProvider(request, app, redirectURI, provider, providerClientId) {
|
|
106
|
+
const { payload, state } = createOAuthState(app, redirectURI);
|
|
107
|
+
const authorizeUrl = createProviderAuthorizeUrl(provider, providerClientId, getCallbackURL(provider), state);
|
|
108
|
+
const headers = new Headers();
|
|
109
|
+
appendCookie(headers, createOAuthStateCookie(request, options, payload));
|
|
110
|
+
return redirect(authorizeUrl.toString(), headers);
|
|
111
|
+
}
|
|
112
|
+
function createProviderAuthorizeUrl(provider, clientId, callbackURL, state) {
|
|
113
|
+
if (provider === "feishu")
|
|
114
|
+
return createFeishuAuthorizeUrl(clientId, callbackURL, state);
|
|
115
|
+
if (provider === "google")
|
|
116
|
+
return createGoogleAuthorizeUrl(clientId, callbackURL, state);
|
|
117
|
+
return createGitHubAuthorizeUrl(clientId, callbackURL, state);
|
|
118
|
+
}
|
|
119
|
+
function createCallbackErrorUrl(provider, error, clientId, redirectURI) {
|
|
120
|
+
const message = error instanceof Error ? error.message : `${getProviderLabel(provider)} 登录失败`;
|
|
121
|
+
return `${authBaseURL}/login?client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(redirectURI)}&error=${encodeURIComponent(message)}`;
|
|
122
|
+
}
|
|
123
|
+
function createGoogleAuthorizeUrl(clientId, callbackURL, state) {
|
|
124
|
+
const authorizeUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
|
|
125
|
+
authorizeUrl.searchParams.set("access_type", "offline");
|
|
126
|
+
authorizeUrl.searchParams.set("client_id", clientId);
|
|
127
|
+
authorizeUrl.searchParams.set("prompt", "select_account");
|
|
128
|
+
authorizeUrl.searchParams.set("redirect_uri", callbackURL);
|
|
129
|
+
authorizeUrl.searchParams.set("response_type", "code");
|
|
130
|
+
authorizeUrl.searchParams.set("scope", (options.google?.scopes ?? ["openid", "email", "profile"]).join(" "));
|
|
131
|
+
authorizeUrl.searchParams.set("state", state);
|
|
132
|
+
return authorizeUrl;
|
|
133
|
+
}
|
|
134
|
+
function createGitHubAuthorizeUrl(clientId, callbackURL, state) {
|
|
135
|
+
const authorizeUrl = new URL("https://github.com/login/oauth/authorize");
|
|
136
|
+
authorizeUrl.searchParams.set("client_id", clientId);
|
|
137
|
+
authorizeUrl.searchParams.set("redirect_uri", callbackURL);
|
|
138
|
+
authorizeUrl.searchParams.set("scope", (options.github?.scopes ?? ["read:user", "user:email"]).join(" "));
|
|
139
|
+
authorizeUrl.searchParams.set("state", state);
|
|
140
|
+
return authorizeUrl;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function createFeishuAuthorizeUrl(appId, callbackURL, state) {
|
|
144
|
+
const authorizeUrl = new URL("https://open.feishu.cn/open-apis/authen/v1/index");
|
|
145
|
+
authorizeUrl.searchParams.set("app_id", appId);
|
|
146
|
+
authorizeUrl.searchParams.set("redirect_uri", callbackURL);
|
|
147
|
+
authorizeUrl.searchParams.set("state", state);
|
|
148
|
+
return authorizeUrl;
|
|
149
|
+
}
|
|
150
|
+
function getProviderDisabledMessage(provider) {
|
|
151
|
+
return `${getProviderLabel(provider)} 登录未配置`;
|
|
152
|
+
}
|
|
153
|
+
function getProviderLabel(provider) {
|
|
154
|
+
if (provider === "feishu")
|
|
155
|
+
return "飞书";
|
|
156
|
+
if (provider === "google")
|
|
157
|
+
return "Google";
|
|
158
|
+
return "GitHub";
|
|
159
|
+
}
|
|
160
|
+
function handleDevLogin(request, options, allowDevLogin, setSessionAndRedirect) {
|
|
161
|
+
if (!allowDevLogin) {
|
|
162
|
+
return json({ error: "开发登录未启用" }, { status: 403 });
|
|
163
|
+
}
|
|
164
|
+
const clientId = getClientId(request, options);
|
|
165
|
+
const app = getApplication(options, clientId);
|
|
166
|
+
const redirectURI = getRedirectURI(request, app);
|
|
167
|
+
if (!isRedirectAllowed(redirectURI, app)) {
|
|
168
|
+
return json({ error: "redirect_uri 不在应用白名单中" }, { status: 400 });
|
|
169
|
+
}
|
|
170
|
+
return setSessionAndRedirect(request, "dev", {
|
|
171
|
+
email: "dev@example.com",
|
|
172
|
+
id: "dev-user",
|
|
173
|
+
metadata: { provider: "dev" },
|
|
174
|
+
name: "开发账号",
|
|
175
|
+
}, app.clientId, redirectURI);
|
|
176
|
+
}
|
|
177
|
+
function handleLogin(request, options, authBaseURL, allowDevLogin) {
|
|
178
|
+
const url = new URL(request.url);
|
|
179
|
+
const clientId = getClientId(request, options);
|
|
180
|
+
const app = getApplication(options, clientId);
|
|
181
|
+
const redirectURI = getRedirectURI(request, app);
|
|
182
|
+
const provider = url.searchParams.get("provider");
|
|
183
|
+
const error = url.searchParams.get("error") ?? undefined;
|
|
184
|
+
if (!isRedirectAllowed(redirectURI, app)) {
|
|
185
|
+
return json({ error: "redirect_uri 不在应用白名单中" }, { status: 400 });
|
|
186
|
+
}
|
|
187
|
+
if (isHostedProvider(provider)) {
|
|
188
|
+
return redirect(createProviderStartUrl(authBaseURL, provider, app.clientId, redirectURI).toString());
|
|
189
|
+
}
|
|
190
|
+
return html(renderLoginPage({
|
|
191
|
+
allowDevLogin,
|
|
192
|
+
app,
|
|
193
|
+
authBaseURL,
|
|
194
|
+
clientId: app.clientId,
|
|
195
|
+
error,
|
|
196
|
+
feishuEnabled: Boolean(options.feishu?.appId && options.feishu?.appSecret),
|
|
197
|
+
githubEnabled: Boolean(options.github?.clientId && options.github?.clientSecret),
|
|
198
|
+
googleEnabled: Boolean(options.google?.clientId && options.google?.clientSecret),
|
|
199
|
+
redirectURI,
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
function isHostedProvider(provider) {
|
|
203
|
+
return provider === "feishu" || provider === "google" || provider === "github";
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/hosted-service/service.ts"],"names":[],"mappings":"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"}
|