deal ali cloud scan login

This commit is contained in:
pikachuim 2025-06-12 17:21:53 +08:00
parent 0998b6c3b0
commit 720fc60365
7 changed files with 306 additions and 125 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ yarn-error.log*
.pnp.js .pnp.js
.vscode/* .vscode/*
.wrangler/*

7
.idea/dictionaries/project.xml generated Normal file
View File

@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>alicloud</w>
</words>
</dictionary>
</component>

28
.idea/workspace.xml generated
View File

@ -4,7 +4,11 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="987ac7e2-ceaa-49a2-b5c9-aed65a7c598d" name="更改" comment="deal merge issue"> <list default="true" id="987ac7e2-ceaa-49a2-b5c9-aed65a7c598d" name="更改" comment="deal ali cloud scan login">
<change afterPath="$PROJECT_DIR$/.idea/dictionaries/project.xml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/aliui.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/oneui.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/public/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/public/index.html" afterDir="false" /> <change beforePath="$PROJECT_DIR$/public/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/public/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.ts" afterDir="false" />
@ -14,6 +18,13 @@
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" /> <option name="LAST_RESOLUTION" value="IGNORE" />
</component> </component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="TypeScript File" />
</list>
</option>
</component>
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
@ -66,7 +77,7 @@
<updated>1749696640494</updated> <updated>1749696640494</updated>
<workItem from="1749696641557" duration="119000" /> <workItem from="1749696641557" duration="119000" />
<workItem from="1749696773818" duration="18000" /> <workItem from="1749696773818" duration="18000" />
<workItem from="1749696801474" duration="15061000" /> <workItem from="1749696801474" duration="20247000" />
</task> </task>
<task id="LOCAL-00001" summary="fin onedrive official token"> <task id="LOCAL-00001" summary="fin onedrive official token">
<option name="closed" value="true" /> <option name="closed" value="true" />
@ -100,7 +111,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1749712420228</updated> <updated>1749712420228</updated>
</task> </task>
<option name="localTasksCounter" value="5" /> <task id="LOCAL-00005" summary="deal merge issue">
<option name="closed" value="true" />
<created>1749714906877</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1749714906877</updated>
</task>
<option name="localTasksCounter" value="6" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -111,6 +130,7 @@
<MESSAGE value="add readme" /> <MESSAGE value="add readme" />
<MESSAGE value="add onedrive area: cn us de" /> <MESSAGE value="add onedrive area: cn us de" />
<MESSAGE value="deal merge issue" /> <MESSAGE value="deal merge issue" />
<option name="LAST_COMMIT_MESSAGE" value="deal merge issue" /> <MESSAGE value="deal ali cloud scan login" />
<option name="LAST_COMMIT_MESSAGE" value="deal ali cloud scan login" />
</component> </component>
</project> </project>

View File

@ -1,4 +1,3 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN" data-theme="light"> <html lang="zh-CN" data-theme="light">
<head> <head>
@ -107,6 +106,7 @@
<option value="onedrive_cn">OneDrive 世纪互联</option> <option value="onedrive_cn">OneDrive 世纪互联</option>
<option value="onedrive_us">OneDrive 美国版本</option> <option value="onedrive_us">OneDrive 美国版本</option>
<option value="onedrive_de">OneDrive 德国版本</option> <option value="onedrive_de">OneDrive 德国版本</option>
<option value="alicloud_qr">阿里网盘 扫码登录</option>
</select> </select>
<div class="mb-3"> <div class="mb-3">
@ -169,7 +169,8 @@
}); });
return; return;
} }
let post_urls = "/onedrive/requests?client_uid=" + apps_uuid let apps_subs = apps_type.split("_")[0]
let post_urls = "/" + apps_subs + "/requests?client_uid=" + apps_uuid
+ "&client_key=" + apps_keys + "&apps_type=" + apps_type; + "&client_key=" + apps_keys + "&apps_type=" + apps_type;
try { try {
const response = await fetch(post_urls, { const response = await fetch(post_urls, {
@ -178,7 +179,33 @@
// 解析响应内容 =============================================== // 解析响应内容 ===============================================
const response_data = await response.json(); const response_data = await response.json();
if (response.status === 200) { if (response.status === 200) {
if (apps_subs === "onedrive") {
window.location.href = response_data.text; window.location.href = response_data.text;
}
if (apps_type === "alicloud_qr") {
let sid = response_data.sid;
await Swal.fire({
position: 'top',
icon: 'info',
title: '扫码登录',
html: `<div>请扫码登录,完成后点确定</div>` +
`<img src="${response_data.text}" alt="">`,
showConfirmButton: true
});
post_urls = "/alicloud/callback" +
"?client_id=" + apps_uuid +
"&client_secret=" + apps_keys +
"&grant_type=" + "authorization_code" +
"&code=" + sid
let auth_post = await fetch(post_urls, {method: 'GET'});
let auth_data = await auth_post.json();
if (auth_post.status === 200) {
window.location.href = `/?access_token=${auth_data.access_token}`
+ `&refresh_token=${auth_data.refresh_token}`
+ `&client_uid=${apps_uuid}`
+ `&client_key=${apps_keys}`;
}
}
} else Swal.fire({ } else Swal.fire({
icon: 'error', icon: 'error',
title: "获取秘钥失败: " + response_data.text, title: "获取秘钥失败: " + response_data.text,

101
src/aliui.ts Normal file
View File

@ -0,0 +1,101 @@
import {Context} from "hono";
const driver_map = [
'https://openapi.aliyundrive.com/oauth/authorize/qrcode',
'https://openapi.aliyundrive.com/oauth/access_token',
'https://openapi.aliyundrive.com/oauth/qrcode',
]
interface AliAccessTokenReq {
client_id: string;
client_secret: string;
grant_type: string;
code: string;
refresh_token: string;
}
interface AliAccessTokenErr {
code: string;
message: string;
error: string;
}
interface AliQrcodeReq {
client_id: string;
client_secret: string;
scopes: string[];
}
// 登录申请 ##############################################################################
export async function alyLogin(c: Context) {
try {
const req: AliQrcodeReq = {
client_id: <string>c.req.query('client_uid'),
client_secret: <string>c.req.query('client_key'),
scopes: ['user:base', 'file:all:read', 'file:all:write']
}
const response = await fetch(driver_map[0], {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(req),
});
if (!response.ok) {
const error: AliAccessTokenErr = await response.json();
return c.json({text: `${error.code}: ${error.message}`}, 403);
}
const data: Record<string, any> = await response.json();
console.log(data);
return c.json({
"text": data.qrCodeUrl,
"sid": data.sid
}, 200);
} catch (error) {
return c.json({text: error}, 500);
}
}
// 令牌申请 ##############################################################################
export async function alyToken(c: Context) {
const req: AliAccessTokenReq = {
client_id: <string>c.req.query('client_id'),
client_secret: <string>c.req.query('client_secret'),
grant_type: <string>c.req.query('grant_type'),
code: <string>c.req.query('code'),
refresh_token: <string>c.req.query('refresh_token')
};
if (req.grant_type !== 'authorization_code' && req.grant_type !== 'refresh_token')
return c.json({text: 'Incorrect GrantType'}, 400);
if (req.grant_type === 'authorization_code' && !req.code)
return c.json({text: 'Code missed'}, 400);
if (req.grant_type === 'refresh_token' && req.refresh_token.split('.').length !== 3)
return c.json({text: 'Incorrect refresh_token or missed',}, 400);
if (req.grant_type === 'authorization_code') {
let code_urls: string = 'https://openapi.aliyundrive.com/oauth/qrcode/' + req.code + '/status'
let auth_post: Response = await fetch(code_urls, {method: 'GET'});
let code_data: Record<string, string> = await auth_post.json();
if (!auth_post.ok || code_data.status !== "LoginSuccess") {
return c.json({text: 'Login failed:' + code_data.status}, 401);
}
req.code = code_data.authCode;
}
try {
const response = await fetch(driver_map[1], {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(req),
});
if (!response.ok) {
const error: AliAccessTokenErr = await response.json();
return c.json({text: `${error.code}: ${error.message}`,}, 403);
}
const data: Record<string, any> = await response.json();
console.log(data);
return c.json(data);
} catch (error) {
return c.json({text: error}, 500
);
}
}

View File

@ -3,132 +3,32 @@ import {KVNamespace} from '@cloudflare/workers-types';
import {serveStatic} from 'hono/cloudflare-workers' // @ts-ignore import {serveStatic} from 'hono/cloudflare-workers' // @ts-ignore
import manifest from '__STATIC_CONTENT_MANIFEST' import manifest from '__STATIC_CONTENT_MANIFEST'
import * as local from "hono/cookie"; import * as local from "hono/cookie";
import * as oneui from './oneui';
import * as aliui from './aliui';
export type Bindings = { export type Bindings = {
MAIN_URLS: string MAIN_URLS: string
} }
const app = new Hono<{ Bindings: Bindings }>() const app = new Hono<{ Bindings: Bindings }>()
app.use("*", serveStatic({manifest: manifest, root: "./"})); app.use("*", serveStatic({manifest: manifest, root: "./"}));
const driver_map: Record<string, string[]> = {
"onedrive_go": [
'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'https://login.microsoftonline.com/common/oauth2/v2.0/token'
],
"onedrive_cn": [
'https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize',
'https://microsoftgraph.chinacloudapi.cn/common/oauth2/v2.0/token'
],
"onedrive_de": [
'https://login.microsoftonline.de/common/oauth2/v2.0/authorize',
'https://graph.microsoft.de/common/oauth2/v2.0/token'
],
"onedrive_us": [
'https://login.microsoftonline.us/common/oauth2/v2.0/authorize',
'https://graph.microsoft.us/common/oauth2/v2.0/token'
],
}
// 登录申请 ############################################################################## // 登录申请 ##############################################################################
app.get('/onedrive/requests', async (c) => { app.get('/onedrive/requests', async (c) => {
const client_uid = <string>c.req.query('client_uid'); return oneui.oneLogin(c);
const client_key = <string>c.req.query('client_key');
const driver_txt = <string>c.req.query('apps_type');
const scopes_all = 'offline_access Files.ReadWrite.All';
const client_url: string = driver_map[driver_txt][0];
// 请求参数 ==========================================================================
const params_all: Record<string, any> = {
client_id: client_uid,
scope: scopes_all,
response_type: 'code',
redirect_uri: 'https://' + c.env.MAIN_URLS + '/onedrive/callback'
};
const urlWithParams = new URL(client_url);
Object.keys(params_all).forEach(key => {
urlWithParams.searchParams.append(key, params_all[key]);
});
// 执行请求 ===========================================================================
try {
const response = await fetch(urlWithParams.href, {
method: 'GET',
});
local.setCookie(c, 'client_uid', client_uid);
local.setCookie(c, 'client_key', client_key);
local.setCookie(c, 'apps_types', driver_txt);
return c.json({text: response.url}, 200);
} catch (error) {
return c.json({text: error}, 500);
}
}) })
// 令牌申请 ############################################################################## // 令牌申请 ##############################################################################
app.get('/onedrive/callback', async (c) => { app.get('/onedrive/callback', async (c) => {
let login_data, client_uid, client_key, driver_txt, client_url, params_all; return oneui.oneToken(c);
try { // 请求参数 ====================================================================
login_data = <string>c.req.query('code');
client_uid = <string>local.getCookie(c, 'client_uid')
client_key = <string>local.getCookie(c, 'client_key')
driver_txt = <string>local.getCookie(c, 'apps_types')
client_url = driver_map[driver_txt][1];
params_all = {
client_id: client_uid,
client_secret: client_key,
redirect_uri: 'https://' + c.env.MAIN_URLS + '/onedrive/callback',
code: login_data,
grant_type: 'authorization_code'
};
} catch (error) {
return c.redirect(
`/?message_err=${"授权失败,请检查: <br>" +
"1、应用ID和应用机密是否正确<br>" +
"2、登录账号是否具有应用权限<br>" +
"3、回调地址是否包括上面地址<br>" +
"4、登录可能过期请重新登录<br>" +
"错误信息: <br> " + error}`
+ `&client_uid=NULL`
+ `&client_key=`);
}
// console.log(login_data);
// 执行请求 ===========================================================================
try {
const paramsString = new URLSearchParams(params_all).toString();
const response: Response = await fetch(client_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: paramsString,
});
// console.log(response);
local.deleteCookie(c, 'client_uid');
local.deleteCookie(c, 'client_key');
local.deleteCookie(c, 'apps_types');
if (!response.ok)
return c.redirect(
`/?message_err=${"授权失败,请检查: <br>" +
"1、应用ID和应用机密是否正确<br>" +
"2、登录账号是否具有应用权限<br>" +
"3、回调地址是否包括上面地址<br>" +
"错误信息: <br>" + response.text()}`
+ `&client_uid=${client_uid}`
+ `&client_key=${client_key}`);
const json: Record<string, any> = await response.json();
if (json.token_type === 'Bearer') {
return c.redirect(
`/?access_token=${json.access_token}`
+ `&refresh_token=${json.refresh_token}`
+ `&client_uid=${client_uid}`
+ `&client_key=${client_key}`);
}
} catch (error) {
return c.redirect(
`/?message_err=${"授权失败,请检查: <br>" +
"1、应用ID和应用机密是否正确<br>" +
"2、登录账号是否具有应用权限<br>" +
"3、回调地址是否包括上面地址<br>" +
"错误信息: <br>" + error}`
+ `&client_uid=${client_uid}`
+ `&client_key=${client_key}`);
}
}) })
// 登录申请 ##############################################################################
app.get('/alicloud/requests', async (c: Context) => {
return aliui.alyLogin(c);
});
// 令牌申请 ##############################################################################
app.get('/alicloud/callback', async (c: Context) => {
return aliui.alyToken(c);
});
export default app export default app

125
src/oneui.ts Normal file
View File

@ -0,0 +1,125 @@
import * as local from "hono/cookie";
import {Context} from "hono";
const driver_map: Record<string, string[]> = {
"onedrive_go": [
'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'https://login.microsoftonline.com/common/oauth2/v2.0/token'
],
"onedrive_cn": [
'https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize',
'https://microsoftgraph.chinacloudapi.cn/common/oauth2/v2.0/token'
],
"onedrive_de": [
'https://login.microsoftonline.de/common/oauth2/v2.0/authorize',
'https://graph.microsoft.de/common/oauth2/v2.0/token'
],
"onedrive_us": [
'https://login.microsoftonline.us/common/oauth2/v2.0/authorize',
'https://graph.microsoft.us/common/oauth2/v2.0/token'
],
}
// 登录申请 ##############################################################################
export async function oneLogin(c: Context) {
const client_uid = <string>c.req.query('client_uid');
const client_key = <string>c.req.query('client_key');
const driver_txt = <string>c.req.query('apps_type');
const scopes_all = 'offline_access Files.ReadWrite.All';
const client_url: string = driver_map[driver_txt][0];
// 请求参数 ==========================================================================
const params_all: Record<string, any> = {
client_id: client_uid,
scope: scopes_all,
response_type: 'code',
redirect_uri: 'https://' + c.env.MAIN_URLS + '/onedrive/callback'
};
const urlWithParams = new URL(client_url);
Object.keys(params_all).forEach(key => {
urlWithParams.searchParams.append(key, params_all[key]);
});
// 执行请求 ===========================================================================
try {
const response = await fetch(urlWithParams.href, {
method: 'GET',
});
local.setCookie(c, 'client_uid', client_uid);
local.setCookie(c, 'client_key', client_key);
local.setCookie(c, 'apps_types', driver_txt);
return c.json({text: response.url}, 200);
} catch (error) {
return c.json({text: error}, 500);
}
}
// 令牌申请 ##############################################################################
export async function oneToken(c: Context) {
let login_data, client_uid, client_key, driver_txt, client_url, params_all;
try { // 请求参数 ====================================================================
login_data = <string>c.req.query('code');
client_uid = <string>local.getCookie(c, 'client_uid')
client_key = <string>local.getCookie(c, 'client_key')
driver_txt = <string>local.getCookie(c, 'apps_types')
client_url = driver_map[driver_txt][1];
params_all = {
client_id: client_uid,
client_secret: client_key,
redirect_uri: 'https://' + c.env.MAIN_URLS + '/onedrive/callback',
code: login_data,
grant_type: 'authorization_code'
};
} catch (error) {
return c.redirect(
`/?message_err=${"授权失败,请检查: <br>" +
"1、应用ID和应用机密是否正确<br>" +
"2、登录账号是否具有应用权限<br>" +
"3、回调地址是否包括上面地址<br>" +
"4、登录可能过期请重新登录<br>" +
"错误信息: <br> " + error}`
+ `&client_uid=NULL`
+ `&client_key=`);
}
// console.log(login_data);
// 执行请求 ===========================================================================
try {
const paramsString = new URLSearchParams(params_all).toString();
const response: Response = await fetch(client_url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: paramsString,
});
// console.log(response);
local.deleteCookie(c, 'client_uid');
local.deleteCookie(c, 'client_key');
local.deleteCookie(c, 'apps_types');
if (!response.ok)
return c.redirect(
`/?message_err=${"授权失败,请检查: <br>" +
"1、应用ID和应用机密是否正确<br>" +
"2、登录账号是否具有应用权限<br>" +
"3、回调地址是否包括上面地址<br>" +
"错误信息: <br>" + response.text()}`
+ `&client_uid=${client_uid}`
+ `&client_key=${client_key}`);
const json: Record<string, any> = await response.json();
if (json.token_type === 'Bearer') {
return c.redirect(
`/?access_token=${json.access_token}`
+ `&refresh_token=${json.refresh_token}`
+ `&client_uid=${client_uid}`
+ `&client_key=${client_key}`);
}
} catch (error) {
return c.redirect(
`/?message_err=${"授权失败,请检查: <br>" +
"1、应用ID和应用机密是否正确<br>" +
"2、登录账号是否具有应用权限<br>" +
"3、回调地址是否包括上面地址<br>" +
"错误信息: <br>" + error}`
+ `&client_uid=${client_uid}`
+ `&client_key=${client_key}`);
}
}