npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@uno-org/request-signing

v0.0.4

Published

Shared request signing protocol utilities for Uno clients

Readme

@uno-org/request-signing

请求签名工具包。它帮你统一生成签名 header,并提供 React Native 和 Web 两个平台的 RSA signer。

你通常只需要关心三件事:

  1. 创建平台 signer。
  2. 登录时把 signer 的 publicKey 传给后端。
  3. 每个请求用同一个 signer 调 createSignedRequest() 注入 header。

安装

Web 项目:

npm install @uno-org/request-signing

React Native 项目:

npm install @uno-org/request-signing react-native-rsa-native react-native-device-info

RN 的两个 native 包需要由业务 app 安装,这样它们才能正常 autolinking。业务代码不需要直接 import 这两个 native 包。

入口

// 通用协议和请求签名
import { createSignedRequest } from '@uno-org/request-signing';

// React Native signer
import { createReactNativeDeviceSigner } from '@uno-org/request-signing/react-native';

// Web signer
import { createWebCryptoRsaDeviceSigner } from '@uno-org/request-signing/web';

不要在 Web 代码里 import /react-native,也不要在 RN 代码里 import /web

React Native 接入

先创建 signer。storagecipher 由业务传入,方便复用项目已有的存储和加密方式。

import { createReactNativeDeviceSigner } from '@uno-org/request-signing/react-native';

const signer = createReactNativeDeviceSigner({
  storage,
  cipher: {
    encrypt,
    decrypt,
  },
  privateKeyStorageKey: 'signature_private',
  publicKeyStorageKey: 'signature_public',
  keySize: 1024,
});

登录时,必须从当前 signer 读取公钥:

const publicKey = await signer.getPublicKey();

await login({
  phoneNumber,
  verifyCode,
  publicKey,
});

请求拦截器里复用同一个 signer:

import {
  EMPTY_BODY_SHA256,
  createSignedRequest,
  stringifyRequestBody,
} from '@uno-org/request-signing';

async function createBodyHash(data: unknown) {
  const body = stringifyRequestBody(data);
  if (!body) return EMPTY_BODY_SHA256;

  return sha256Hex(body);
}

const signed = await createSignedRequest({
  signer,
  method: config.method || 'get',
  url: axiosInstance.getUri(config),
  bodyHash: await createBodyHash(config.data),
});

Object.entries(signed.headers).forEach(([key, value]) => {
  headers.set(key, value);
});

当你需要重置签名 key 时,必须同步清理 token,并在下一次登录前重新读取 publicKey

await signer.clear();
await removeAccessToken();
const publicKey = await signer.getPublicKey();

RN RSA signer 支持用当前 public key 做本地自检。这个能力适合在启动时确认本地 private key 和 public key 是否仍是一组:

const message = 'signature-health-check';
const signature = await signer.sign(message);
const verified = await signer.verify(message, signature);

需要校验外部 public key 时,也可以显式传入第三个参数:

const verified = await signer.verify(message, signature, publicKey);

Web 接入

Web 侧使用 WebCrypto signer。业务需要提供 keyStore,决定 key pair 如何持久化。

import { createWebCryptoRsaDeviceSigner } from '@uno-org/request-signing/web';

const signer = createWebCryptoRsaDeviceSigner({
  keyStore,
  getDeviceId,
});

然后和 RN 一样,登录传 publicKey,请求时调用 createSignedRequest()

const publicKey = await signer.getPublicKey();
await login({ publicKey });

const signed = await createSignedRequest({
  signer,
  method: 'get',
  url: '/user/info',
});

WebCrypto 需要 HTTPS 或 localhost。业务侧在不支持 crypto 的环境里需要阻止签名请求或走降级逻辑。

公钥一致性

这是最容易出问题的地方:登录时传给后端的 publicKey,必须和后续签名请求用的 private key 属于同一组 key pair。

正确做法:

const publicKey = await signer.getPublicKey();
await login({ publicKey });

await createSignedRequest({
  signer,
  method,
  url,
  bodyHash,
});

不要把 publicKey 长期缓存成业务状态后直接用于登录。退出登录、token 过期、重置 key 时,如果只删 storage 但内存 signer 还拿着旧 key,就可能出现 token 中的 public key 和本地 private key 不匹配,后续接口会一直验签失败。

协议说明

createSignedRequest() 生成的签名内容固定为:

METHOD
PATH_WITH_QUERY
BODY_SHA256
TIMESTAMP
NONCE

生成的 header 包括:

  • x-device-id
  • x-timestamp
  • x-nonce
  • x-body-sha256
  • x-signature
  • x-key-id

服务端验签时必须使用同样的 body stringify 和 hash 规则。

发布前检查

pnpm --filter @uno-org/request-signing typecheck
pnpm exec vitest run packages/request-signing/src/index.test.ts packages/request-signing/src/signer.test.ts packages/request-signing/src/react-native-rsa-signer.test.ts packages/request-signing/src/react-native/index.test.ts packages/request-signing/src/web-crypto-rsa-signer.test.ts
pnpm --filter @uno-org/request-signing build
npm pack --dry-run --json

发布前确认 npm tarball 中包含:

  • dist/index.*
  • dist/react-native/*
  • dist/web/*
  • README.md