用Cloudflare Workers搭建免费OneDrive网盘

由 CloudFlare Workers 强力驱动的 OneDrive 索引

在线演示:WuYang’s Disk

演示还是我那30多G的妹子图……
共享一波妹子图
由于囊中羞涩没有继续部署 PHP 版本的 OneIndex 了.
换用 OneIndex-CF-Index 后可以获得 Cloudflare-Workers 每日 1W PV的免费请求.


2021-03-19 程序已换到更强大的 OnePoint
例:WuYang’s Disk from CF Workers | WuYang’s Disk from Vercel
支持网盘更多,支持部署的平台更多,如 传统服务器、CF Workers、腾讯云函数、Vercel 等


本文大部分内容抄自官方文档,但是补充了亲自部署时候遇到的问题和解决方法.

功能

🚀 功能一览

  • 全新「面包屑」导航栏;
  • 令牌凭证由 Cloudflare Workers 自动刷新,并保存于(免费的)全局 KV 存储中;
  • 使用 Turbolinks® 实现路由懒加载;
  • 支持由世纪互联运营的 OneDrive 版本;
  • 支持 SharePoint 部署;

🗃️ 目录索引显示

  • 全新支持自定义的设计风格:spencer.css
  • 支持使用 Emoji 作为文件夹图标(如果文件夹名称第一位是 Emoji 则自动开启该功能);
  • 渲染 README.md 如果当前目录下包含此文件,使用 github-markdown-css 渲染样式;
  • 支持「分页」,没有一个目录仅限显示 200 个项目的限制了!

📁 文件在线预览

  • 根据文件类型渲染文件图标,图标使用 Font Awesome icons
  • 支持预览:
    • 纯文本:.txt.
    • Markdown 格式文本:.md, .mdown, .markdown.
    • 图片(支持 Medium 风格的图片缩放):.png, .jpg, and .gif.
    • 代码高亮:.js, .py, .c, .json
    • PDF(支持懒加载、加载进度、Chrome 内置 PDF 阅读器):.pdf.
    • 音乐:.mp3, .aac, .wav, .oga.
    • 视频:.mp4, .flv, .webm, .m3u8.

🔒 私有文件夹

我们可以给某个特定的文件夹(目录)上锁,需要认证才能访问。我们可以在 src/auth/config.js 文件中将我们想要设为私有文件夹的文件夹名称写入 ENABLE_PATHS 列表中,并将 AUTH_ENABLED 设置为 true 来开启这一功能。我们还可以自定义认证所使用的用户名 NAME 以及密码,其中认证密码保存于 AUTH_PASSWORD 环境变量中,如果需要这一功能,则需要使用 wrangler 来设置这一环境变量:

1
2
wrangler secret put AUTH_PASSWORD
# 在这里输入你自己的认证密码

这里注意,别略过!!!待会部署提交预览之前一定要设置,或者按照下面的提示关掉。不然会提示Uncaught ReferenceError: AUTH_PASSWORD is not defined

如果不需要开启这一功能,那么你可以直接注释掉定义 PASS 变量的那一行,使用下一行将 PASS 设置为空字符串即可。(另外也需要将 AUTH_ENABLED 设置为 false。)有关 wrangler 的使用细节等详细内容,请参考 接下来的部分段落

⬇️ 代理下载文件 / 文件直链访问 / 缩略图

  • [可选] Proxied download(代理下载文件):?proxied - 经由 CloudFlare Workers 下载文件。要满足两个条件(1)config/default.js 中的 proxyDownloadtrue,以及(2)使用参数 ?proxied 请求文件;
  • [可选] Raw file download(文件直链访问):?raw - 返回文件直链而不是预览界面;
  • 两个参数可以一起使用,即 ?proxied&raw?raw&proxied 均有效。

补充,缩略图的获取方式

是的,这也就意味着你可以将这一项目用来搭建「图床」,或者用于搭建静态文件部署服务,比如下面的图片链接:

1
2
3
4
5
6
7
8
#small 96px
https://wuyang.ws/***.jpg?proxied&thumbnail=small

#medium 176px
https://wuyang.ws/***.jpg?proxied&thumbnail=medium

#large 800px
https://wuyang.ws/***.jpg?proxied&thumbnail=large



部署指南

又臭又长的中文版部署指南预警!

生成 OneDrive API 令牌

  1. 访问此 URL 创建新的 Blade app:Microsoft Azure App registrations(普通版 OneDrive)或 Microsoft Azure.cn App registrations(OneDrive 世纪互联版本),建议将语言设置为「英语」以保证以下步骤中提到的模块和按钮的名称一致

    1. 使用你的 Microsoft 账户登录,选择 New registration
    2. Name 处设置 Blade app 的名称,比如 my-onedrive-cf-index
    3. Supported account types 设置为 Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)。OneDrive 世纪互联用户设置为:任何组织目录(任何 Azure AD 目录 - 多租户)中的帐户
    4. Redirect URI (optional) 设置为 Web(下拉选项框)以及 https://localhost(URL 地址);
    5. 点击 Register.

  2. Overview 面板获取你的 Application (client) ID - client_id

  3. 打开 Certificates & secrets 面板,点击 New client secret,创建一个新的叫做 client_secret 的 Client secret,并将 Expires 设置为 Never。点击 Add 并复制 client_secretValue 并保存下来 (仅有此一次机会)

  4. 打开 API permissions 面板,选择 Microsoft Graph,选择 Delegated permissions,并搜索 offline_access, Files.Read, Files.Read.All 这三个权限,选择这三个权限,并点击 Add permissions

    你应该成功开启这三个权限:

  5. 获取 refresh_token

    • 本地获取 (需要 Node.js 和 npm 环境,安装和推荐配置请参考 准备工作)上面执行如下命令:
    1
    npx @beetcb/ms-graph-cli


    根据你自己的情况选择合适的选项,并输入我们上面获取到的一系列 token 令牌配置等,其中 redirect_url 可以直接设置为 http://localhost。有关命令行工具的具体使用方法请参考:beetcb/ms-graph-cli

    • 在线获取

    访问:Microsoft Graph API Auth 获取

  1. 最后,在我们的 OneDrive 中创建一个公共分享文件夹,比如 /Public 即可。建议不要直接分享根目录!

    最后,这么折腾完,我们应该成功拿到如下的几个凭证:

    • refresh_token
    • client_id
    • client_secret
    • redirect_uri
    • base:默认为 /Public

    是,我知道很麻烦,但是这是微软,大家理解一下。🤷🏼‍♂️

准备工作

Fork 再 clone 或者直接 clone onedrive-cf-index,并安装依赖 Node.js、npm 以及 wrangler

强烈建议大家使用 Node version manager 比如 n 或者 nvm 安装 Node.js 和 npm,这样我们全局安装的 wrangler 就可以在我们的用户目录下安装保存配置文件了,也就不会遇到奇奇怪怪的权限问题了。

以下直接用npm安装可能失败,请看本节可能遇到的问题

1
2
3
4
5
6
7
8
9
10
11
# 安装 CloudFlare Workers 官方编译部署工具
npm i @cloudflare/wrangler -g

# 使用 npm 安装依赖
npm install

# 使用 wrangler 登录 CloudFlare 账户
wrangler login

# 使用这一命令检查自己的登录状态
wrangler whoami

打开 https://dash.cloudflare.com/login 登录 CloudFlare,选择自己的域名,再向下滚动一点,我们就能看到右侧栏处我们的 account_id 以及 zone_id 了。 同时,在 Workers -> Manage Workers -> Create a Worker 处创建一个 DRAFT worker。

修改我们的 wrangler.toml

  • name:就是我们刚刚创建的 draft worker 名称,我们的 Worker 默认会发布到这一域名下:<name>.<worker_subdomain>.workers.dev
  • account_id:我们的 Cloudflare Account ID;
  • zone_id:我们的 Cloudflare Zone ID。

创建叫做 BUCKET 的 Cloudflare Workers KV bucket:

1
2
3
4
5
# 创建 KV bucket
wrangler kv:namespace create "BUCKET"

# ... 或者,创建包括预览功能的 KV bucket
wrangler kv:namespace create "BUCKET" --preview

修改 wrangler.toml 里面的 kv_namespaces

  • kv_namespaces:我们的 Cloudflare KV namespace,仅需替换 id 和(或者)preview_id 即可。如果不需要预览功能,那么移除 preview_id 即可。

修改 src/config/default.js

  • client_id:刚刚获取的 OneDrive client_id
  • base:之前创建的 base 目录;
  • 如果你部署常规国际版 OneDrive,那么忽略以下步骤即可;
  • 如果你部署的是由世纪互联运营的中国版 OneDrive:
    • 修改 type 下的 accountType1
    • 保持 driveType 不变;
  • 如果你部署的是 SharePoint 服务:
    • 保持 accountType 不变;
    • 修改 driveType 下的 type1
    • 并根据你的 SharePoint 服务修改 hostNamesitePath

使用 wrangler 添加 Cloudflare Workers 环境变量:

1
2
3
4
5
6
# 添加我们的 refresh_token 和 client_secret
wrangler secret put REFRESH_TOKEN
# ... 并在这里粘贴我们的 refresh_token

wrangler secret put CLIENT_SECRET
# ... 并在这里粘贴我们的 client_secret

本节可能遇到的问题

如果你是用本地获取refresh_token的需要修改redirect_urihttp://localhost

npm i @cloudflare/wrangler -g 出错 Error: EACCES: permission denied, access '/usr/lib/node_modules'
安装wrangler的时候权限不足,即使sudo npm i @cloudflare/wrangler -g也会出错
这时候只能给它安装到当前项目了。

1
npm install @cloudflare/wrangler --save

注意,即使使用 sudo npm install -g @cloudflare/wrangler --unsafe-perm=true --allow-root 后面也会不能正常使用

编译与部署

我们可以使用 wrangler 预览部署:

1
wrangler preview

如果一切顺利,我们即可使用如下命令发布 Cloudflare Worker:

1
wrangler publish

本节可能遇到的问题

  • 错误内容getAccessToken
    如果你确定上面填写的内容都正常,那么可能是遇到了refresh_token过长secret保存失败……

    解决方法:使用KV来保存refresh_token

    首先还是一样的操作,拿到 refresh_token 之后,在 Cloudflare Workers → KV 里面的 BUCKET namespace 中创建一个新的 entry 就叫做 refresh_token,然后把你拿到的 refresh_token 粘进去:

    之后修改代码,在 ./src/auth/onedrive.js 里面加一个获取 refresh_token 的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // ...
    export async function getAccessToken() {
    const timestamp = () => {
    return Math.floor(Date.now() / 1000)
    }

    const refresh_token = await BUCKET.get('refresh_token')

    // 之后所有的 config.refresh_token 都直接改为 refresh_token
    // ...
    }

    顺便还要把其他原有定义了 REFRESH_TOKEN 的地方删掉(比如 ./src/config/default.js 里面的 refresh_token: REFRESH_TOKEN, 一行)。

样式、内容的自定义

  • 我们 应该 更改默认「着落页面」,直接修改 src/folderView.js#L51-L55) 中 intro 的 HTML 即可;
  • 我们也 应该 更改页面的 header,直接修改 src/render/htmlWrapper.js#L24 即可;
  • 样式 CSS 文件位于 themes/spencer.css,可以根据自己需要自定义此文件,同时也需要更新 src/render/htmlWrapper.js#L3 文件中的 commit HASH;
  • 我们还可以自定义 Markdown 渲染 CSS 样式、PrismJS 代码高亮样式,等等等。

如果遇到图片无法显示缩略图

如果使用的不是个人版OneDrive,下面带Crop的选项可能无法正常显示缩略图

NameResolutionAspect RatioDescription
small96 longestOriginalSmall, highly compressed thumbnail cropped to a square aspect ratio.
medium176 longestOriginalCropped to the standard item size for the OneDrive web view.
large800 longestOriginalThumbnail with the longest edge resized to 800 pixels.
smallSquare96x96Square Crop该选项不可用,会返回itemNotFound错误
mediumSquare176x176Square Crop该选项不可用,会返回itemNotFound错误
largeSquare800x800Square Crop该选项不可用,会返回itemNotFound错误
1
2
https://wuyang.ws/***.jpg?proxied&thumbnail=c300x400  #正常
https://wuyang.ws/***.jpg?proxied&thumbnail=c300x400_Crop #不可用

最后,感谢作者 Spencer Woo. 为我们带来如此强大的程序!