Cloudflare Worker Secret doc
极简、开源端到端加密的阅后即焚文档。
功能特点
- 🔒 安全加密:使用 AES -GCM 加密保护文档内容
- ⏰ 自动销毁:支持设置查看次数和有效期
- 📝 Markdown:支持 Markdown 格式的文档
- 🎨 夜间模式:夜间护眼不可少
- 🔄 实时倒计时:显示剩余查看次数、剩余时间
- 📋 一键复制:自动复制分享链接到剪贴板
- 💥 手动销毁:支持手动立即销毁文档
- 🌐 边缘计算:基于 Cloudflare Worker,全球极速访问
- 🛡️ 校验链接:防止机器自动扫描
- 📌 自定义分享链接:支持自定义分享链接路径和类型
使用方法
- 访问并创建 Cloudflare 账号,Compute - Workers和Pages - 创建 - 创建应用程序,从 Hello World! 开始,名称保持默认或者随意设置,点击部署,然后编辑代码,把原来的代码删除,然后把仓库里
Cloudflare Worker Secret doc.js 的内容复制并粘贴到代码处,点击部署;
- 如果想自定义分享路径、分享ID类型等,见代码头部的注释;
- 返回Cloudflare首页,存储和数据库 - Workers KV,新建一个KV,名称随意,进入刚才创建的workers,点击设置 - 绑定 - 添加 - KV命名空间,变量名称填
Worker_Secret_doc 找到刚新建的KV,KV命名空间选择刚才创建的KV,点击保存即可使用Cloudflare提供的默认域名访问;
- 自定义域名:添加域名到Cloudflare后,Workers和Pages - 找到秘密文档的 workers - 设置 - 域和路由 - 添加 - 自定义域,添加自己域名即可;例如:你的域名是 doc.com 那么可以添加 mimi.doc.com ;
- 阻止恶意访问需要在Cloudflare防火墙设置规则;
- 如果想删数据,进入KV按文档ID删除,或者删除整个KV。
部分代码
const getHomePageContent = () => `
<div class="header-section" style="text-align: center; margin-bottom: 8px; flex-shrink: 0;">
<p style="margin: 0; font-size: 16px; color: var(--text-color); opacity: 0.8;">让你的秘密在☁️飞一会 ✈️</p>
</div>
<div class="form-section" style="flex: 1; display: flex; flex-direction: column; min-height: 0;">
<div class="form-group" style="margin-bottom: 8px; flex: 1; display: flex; flex-direction: column; min-height: 0;">
<div class="editor-wrapper" style="position: relative; flex: 1; min-height: 300px;">
<textarea id="markdownText" class="editor-box" placeholder="请输入你的秘密📄,支持 MarkDown 格式。" maxlength="100000" oninput="updateCharCount()"></textarea>
<div style="position: absolute; bottom: 5px; right: 5px; font-size: 12px; color: var(--text-color); opacity: 0.7; z-index: 5;">
<span id="charCount">0</span>/100000
</div>
<button type="button" id="previewToggle" onclick="togglePreview()" style="background-color: #1E90FF; position: absolute; top: 5px; right: 5px; padding: 4px 8px; font-size: 12px; width: auto; z-index: 10; margin: 0;">预览</button>
<div id="previewContainer" class="editor-box" style="display: none; background-color: var(--bg-color); border: 1px solid var(--border-color); padding: 10px;">
<article class="markdown-body" id="previewContent" style="height: 100%; overflow-y: auto;"></article>
</div>
</div>
</div>
<div class="options-grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 0; flex-shrink: 0;">
<div class="form-group" style="display: flex; align-items: center; gap: 6px; height: 38px; margin-bottom: 0;">
<label for="views" style="margin: 0; flex-shrink: 0; font-size: 14px; color: var(--text-color); line-height: 38px;">⌛ 查看次数:</label>
<div style="flex: 1; position: relative; display: flex; align-items: center;">
<input type="number" id="views" value="1" min="1" max="10000" step="1" oninput="this.value = this.value.replace(/[^0-9]/g, '')" style="width: 100%; height: 32px; margin: 0;">
</div>
</div>
<div class="form-group" style="display: flex; align-items: center; gap: 6px; height: 38px; margin-bottom: 0;">
<label for="expiration" style="margin: 0; flex-shrink: 0; font-size: 14px; color: var(--text-color); line-height: 38px;">⏲️ 有效期:</label>
<div style="flex: 1; position: relative; display: flex; align-items: center;">
<input type="number" id="expiration" value="1440" min="1" step="1" oninput="this.value = this.value.replace(/[^0-9]/g, '')" style="width: 100%; height: 32px; margin: 0;">
</div>
<small style="flex-shrink: 0; font-size: 12px; color: var(--text-color); opacity: 0.7; line-height: 38px; margin: 0;">分钟</small>
</div>
</div>
<div class="password-section" style="margin-top: 8px; margin-bottom: 0; height: 38px; flex-shrink: 0;">
<div style="display: flex; align-items: center; gap: 6px; height: 100%;">
<label for="password" style="margin: 0; flex-shrink: 0; font-size: 14px; color: var(--text-color); line-height: 38px;">🔒 密码:</label>
<div style="flex: 1; position: relative; display: flex; align-items: center;">
<input type="password" id="password" placeholder="可选,设置密码加密" style="width: 100%; height: 32px; margin: 0;">
<div style="position: absolute; right: 5px; top: 50%; transform: translateY(-50%); display: flex; gap: 5px;">
<button type="button" onclick="generateRandomPassword('password')" style="background-color: #1E90FF; padding: 2px 6px; font-size: 12px; width: auto; height: auto; margin: 0;">随机密码</button>
<button type="button" onclick="togglePasswordVisibility('password')" style="background-color: #1E90FF; padding: 2px 6px; font-size: 12px; width: auto; height: auto; margin: 0;">显示</button>
</div>
</div>
</div>
</div>
<div style="margin-top: 8px; height: 38px; flex-shrink: 0;">
<button onclick="createDocument()" style="background-color: #1E90FF; width: 100%; height: 100%; font-size: 16px; font-weight: bold; margin: 0;">生成端到端加密链接 🔗</button>
</div>
<style>
.editor-box {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
border-radius: 4px;
box-sizing: border-box;
overflow-y: auto;
}
#markdownText {
background-color: var(--bg-color);
color: var(--text-color);
border: 1px solid var(--border-color);
padding: 10px;
resize: none;
}
@media (max-width: 768px) {
.options-grid { grid-template-columns: 1fr; }
.form-section > .form-group:first-child { flex: none; height: 40vh; min-height: 200px; max-height: 400px; }
.editor-wrapper { min-height: auto; }
}
</style>
</div>
<div class="link-section" style="margin-top: 8px; flex-shrink: 0;">
<div id="linkContainer" style="background-color: var(--code-bg-color); border: 1px solid var(--border-color); border-radius: 4px; padding: 8px; display: none; align-items: flex-start; gap: 6px; flex-wrap: wrap; min-height: 38px; box-sizing: border-box;">
<h3 style="margin: 0; font-size: 14px; color: var(--text-color); flex-shrink: 0; line-height: 22px;">分享链接:</h3>
<p id="link" onclick="copyLink()" style="margin: 0; word-wrap: break-word; color: var(--link-color); cursor: pointer; flex: 1; min-width: 0; line-height: 22px; font-size: 14px;"></p>
</div>
</div>
<div class="notification" id="notification">✅ 链接已复制到剪贴板</div>
<div style="margin-top: auto; text-align: center; font-size: 14px; color: var(--text-color); opacity: 0.8; padding-top: 10px; border-top: 1px solid var(--border-color);">
<p style="margin: 0;">秘密文档 - 极简、<a href="https://github.com/fzxx/Cloudflare-Worker-Secret-doc" target="_blank" rel="noopener noreferrer" style="color: var(--link-color); text-decoration: none;">开源</a>端到端加密的阅后即焚文档。 | © 风之暇想 | v1.5</p>
</div>
`;
疑问
带预览链接功能的即时通讯软件、邮件,会导致链接被机器访问而失效,如何解决?
- 限制次数设置为2次或更多
- 用Cloudflare防火墙把它们拦截下来(根据UA、地区等)
限制文本大小是?
- 由于免费的KV空间只有1G,因此限制每个文档的大小是100KB
KV空间满了,如何清理?
- 进入KV命名空间删除整个KV,重新创建并再次绑定;不设置自动清理是因为Api计次的,自动清理会耗尽次数。
更新日志、下载地址
Cloudflare-Worker-Secret-doc
|