@ gainratio/ 浏览器
对于 Web 开发者: 请检查下载的数据由您签名而不更改的浏览器, 然后保存到离线使用 .
npm install @gainratio/browser (第0.4.6版; @edgeproc/browser 是旧名, 已贬值)
文档 : 浏览器. contratio.com • 妇女 开始 • 妇女 实例
许多网络应用下载数据文件,并在页面内与他们合作:一个产品目录,a 搜索索引,价格列表,模型. 该页面信任服务器或CDN发送回的任何内容 . 如果镜像为旧副本服务,或者文件在路上被更改或缩短,则应用程序使用它 无论如何,没有人注意到.
此软件包让页面检查数据本身 。 你公布数据一次 这个 页面在背景线条( Web Worker)中下载,检查您的签名和 拒绝任何不符合要求的东西 它把检查的副本放在 浏览器,所以下一次访问的下载仅是更改了哪些内容,仍然在下线工作. 阿尔马梅什 用它来下载它的图表引擎.
技术文件: 建筑 • 妇女 API 指南 • 妇女 开始开发者 • 妇女 警卫
试试看
你需要节点22.13或更新,和 页:1 运行 Python 工具 签名的数据。 这大约需要一分钟.
-
制作一个项目并安装软件包, 加上 Vite 服务页面 :
mkdir signed-data-demo && cd signed-data-demo npm init -y npm install @gainratio/browser vite -
与
edgeproc从 Python 命令edge-proc软件包 :mkdir data echo '{"sku": "A-100", "name": "Blue mug", "price": 12.5}' > data/prices.json uvx --from 'edge-proc[bundles]' edgeproc keygen --out keys uvx --from 'edge-proc[bundles]' edgeproc publish --src data --origin-dir public/bundle \ --key keys/private.key --bundle-id prices --version v1 --sequence 1 cp keys/public.key public/public.keykeygen指纹wrote keys/private.key and keys/public.key和钥匙身份.publish将签名的指针打印为 JSON.public/bundle现在持有该指针( a)latest页:1 文件列表( e)manifest/)和数据为零(chunk/) (中文(简体) ). 保留--sequence 1页:1 浏览器拒绝一个没有序列号的捆绑, 你每次提高它 发布. -
增加一页. 创建这三个文件 :
edgeproc.worker.jsimport "@gainratio/browser/worker";main.jsimport { EngineClient } from "@gainratio/browser"; import EdgeProcWorker from "./edgeproc.worker.js?worker"; const out = document.querySelector("#out"); const client = new EngineClient(new EdgeProcWorker()); try { const result = await client.sync("/bundle", "/public.key"); const bytes = await client.readFile("prices.json"); out.textContent = `verified ${result.version} (${result.chunksFetched} fetched, ${result.chunksReused} reused)\n` + new TextDecoder().decode(bytes); } catch (error) { out.textContent = `refused (${error.code}): ${error.message}`; }index.html<!doctype html> <h1>Signed data check</h1> <pre id="out" style="white-space: pre-wrap; word-break: break-all">checking...</pre> <script type="module" src="/main.js"></script> -
运行
npx vite并开放http://localhost:5173. 页面下载捆绑,检查它, 并显示文件 :
重新装入页面 。 它现在说
verified v1 (0 fetched, 1 reused): 检查的副本是 已存储在浏览器中, 因此没有再下载 . -
现在玩一面糟糕的镜子。 更改所存储数据块的一个字节 :
node -e "const fs=require('fs'),d='public/bundle/chunk/',p=d+fs.readdirSync(d)[0],b=fs.readFileSync(p);b[9]^=1;fs.writeFileSync(p,b)"在一个新的私人窗口中打开 http://localhost:5173。 页面拒绝数据而不是 显示它:

refused (integrity): chunk 34fa454858ceada20cfa0cd5236eb70f90e1021ed3bd03a6c9d5332597b3cc12 failed content-address check需要一个私人窗口, 因为您正常的窗口已经持有选中的副本 不再下载该作品。 运行
node -e线条将再次取消更改.
没有浏览器吗? 节点的相同检查
检查核心也在节点运行. 另存为 check.mjs 在同一文件夹中运行
node check.mjs (数据不变). "服务器"是一个读取本地
文件,第二次运行会翻转它所服务的每一件文件中的一个字节:
import { readFile } from "node:fs/promises";
import { MemoryCacheStore, materializeFile, syncIndex, verifyEd25519 } from "@gainratio/browser";
const key = new Uint8Array(await readFile("public/public.key"));
const verify = (message, signature) => verifyEd25519(key, message, signature);
// Stands in for a web server: "/bundle/latest" is read from public/bundle/latest.
const server = async (url) => new Uint8Array(await readFile(`public${url}`));
// A bad mirror: flips one byte in every data chunk it serves.
const tampered = async (url) => {
const bytes = await server(url);
if (url.includes("/chunk/")) bytes[9] ^= 1;
return bytes;
};
const store = new MemoryCacheStore();
const ok = await syncIndex({ baseUrl: "/bundle", store, fetchBytes: server, verify });
const manifest = JSON.parse(new TextDecoder().decode(await store.getManifest(ok.manifestHash)));
const bytes = await materializeFile(store, manifest, "prices.json");
console.log(`accepted ${ok.version}: ${new TextDecoder().decode(bytes).trim()}`);
await syncIndex({ baseUrl: "/bundle", store: new MemoryCacheStore(), fetchBytes: tampered, verify })
.catch((error) => console.log(`refused: ${error.name}: ${error.message}`));
accepted v1: {"sku": "A-100", "name": "Blue mug", "price": 12.5}
refused: IntegrityError: chunk 34fa454858ceada20cfa0cd5236eb70f90e1021ed3bd03a6c9d5332597b3cc12 failed content-address check
如何运作
出版商将您的文件切成块, 每个作品的名称 以散列的内容
签名一个小指针文件,以命名棋子列表。 您的页面给出了捆绑的 URL
和公钥 URL 到一个 Web Worker。 工人检查指针的签名
您的密钥, 拒绝比它已有的更老的指针, 然后下载
残片不见了, 检查每个与它的散列。 只有在一切过去的时候
新版本替换了浏览器存储中的旧版本: OPFS上的一个SQLite数据库,
或拒绝OPFS(该副本在下个会话中被重新下载)的记忆中。 过
cacheFallback: "none" 拒绝回扣:同步后立即拒绝回扣
EngineStorageUnavailableError 而不下载任何内容。 任意
失败是输入错误, 最后的好版本会保留 .
工作人員也把每个网络请求都报告回页面,这样你就可以数了
他们。 当你的捆绑包含 .sqlite 数据库(例如产品目录或
引用数据集),工作人打开了以全文在 OPFS 中验证的 SQLite 文件
搜索( FTS5 )、 JSON1 和向量搜索, 以及未来的更新只下载 64 KB 块
这改变了。 更多进去 建筑 财务报告和审定财务报表
浏览器中的 SQL。 。 。 .
它不会做的
- 它不签署或公布数据. 你需要一个出版商 今天,这是
蟒
edgeproc publish命令上显示. - 数据流动方式之一从发布器到浏览器。 它不同步用户编辑回一个 服务器.
- 它不知道你的数据是什么意思. 它会递给你的应用检查字节 他们是什么 这取决于你.
- 它不能保护一个被损坏的页面. 恶意浏览器扩展或攻击者 控制您的公用钥匙 URL, 是无法联系的。 从自己处为 HTTPS 提供密钥 站点,与数据不同。 将私钥从网络服务器上关闭.
- Chromium获得完整的浏览器套件;Firefox和WebKit获得一个交叉浏览器测试. 单位
CI,Firefox和WebKit运行 OPFS 打开,内存倒计时,一个SQL回程,
出/入和内存图示检测。 Playwright 的 WebKit 拒绝 OPFS, 所以这里有
测试
opfs-unavailable倒计时,不是OPFS本身. 真正的Safari没有测试. - 早释. 0.1.1是第一个版本
@gainratio/browser和第一个 由CI发布 npm出处.@edgeproc/browser0.1.0 手头出版 无出处;此名被贬. - 可选的 SQLite app- state 商店需要交叉发端的页面(COOP和COEP) (原始内容存档于2018-10-21). Headers. 其他的包裹没有.
什么时候用别的东西
| 狦 | 使用 |
|---|---|
| 完全信任您的服务器和每个 CDN 在两者之间 | 平面 fetch 超过 HTTPS |
| 拥有一些您在构建时可以放入 HTML 的文件 | 分资源integrity= 在脚本或链接标签上) |
| 想要你的应用程序自己的代码和页面离线工作 | 服务- 员工缓存, 如 Workbox |
| 需要用户编辑才能返回共享服务器 | 同步的主机数据库 |
| 用 Python 运行设备, 而不是浏览器 | 活猫 edge-proc 库,它使用相同的捆绑格式 |
| 在不移动页面的情况下更改的船载数据, 并且希望页面拒绝您没有签名的任何内容 | 这个包 |
安装
npm install @gainratio/browser
此 README 文档 0.4. 6 , 它与 main 时间
写作的时间。 Pnpm和Bun也会工作。 换句话说
pnpm add github:gainratio/edgeproc-browser#<commit-sha>。 。 。 .
除主要进口外,还有用于工人入境的分路径进口,未捆绑用途, 矢量搜索, 和 SQLite 状态 。 这个 API 指南 列出所有例子.
开发
使用节点 24 (节点 26 打破了 corepack pnpm shim)和 pnpm 11.5.0 通过 corepack:
git clone https://github.com/gainratio/edgeproc-browser
cd edgeproc-browser
corepack enable
pnpm install --frozen-lockfile
pnpm gate
pnpm gate 运行 lint, 类型检查, 构建, 检查已承诺 dist/ 匹配一个
干净的建筑, 和单位测试覆盖。 这是相同的指令CI运行,并带走
在一分钟内. pnpm test:browser 运行CI也运行的真浏览器测试(Chrimium,外加Firefox和WebKit的交叉浏览器测试). 见
开始开发者 对于一个代码地图, 已知的本地陷阱,
以及第一次改变.
详细情况
- 建筑: 捆绑格式、检查什么、每次拒绝 和那些试验所证实的.
- 交互式架构映射: 可单击 运行时间.
- API 指南: 配备 Vite 、 密钥环和密钥旋转、 计数的工人设置 网络请求,向量搜索,SQLite app状态,以及每个选项.
- 开始开发者设置,运行检查,和制作 a 第一个变化.
- SQLite 状态商店:迁移,备份,信头和所有权.
- SQLite 内存简介:页面缓存和堆积限制大小到设备.
- 浏览器中的 SQL:一个OPFS SQLite数据库,有FTS5,JSON1和向量, 在图书馆的工人.
- 密码句文件: 以密码句加密备份为标准年龄
文件编号
age命令行工具也可以打开. - 依赖关系:为什么每个依赖在这里.
- 警卫:威胁模型,关键旋转,以及如何报告脆弱性.
- 捐款额:什么是变化需要,什么被推后.
- 变动情况:每个版本的变化.
许可证
麻省理工学院. 见 自由主义。 。 。 .