genkey
generateAppKey.js
const SEA = require('gun/sea');
// 生成密钥对
SEA.pair().then((pair) => {
// 输出提示信息
console.log('This is your secret app key pair.\nAdd this to your .dotenv file:');
// 将生成的密钥对转换为 JSON 格式并输出
console.log(`APP_KEY_PAIR='${JSON.stringify(pair)}'`);
});
$ node ./generateAppKey.js
Hello wonderful person! :) Thanks for using GUN, please ask for help on http://chat.gun.eco if anything takes you longer than 5min to figure out!
This is your secret app key pair.
Add this to your .dotenv file:
APP_KEY_PAIR='{"pub":"B14-m6S3i1cgm9bJCsED0FsGbHiDlXJAiKK2OnrPSj0.axmMDTmbdAfU3SjJhgqOn6mH6jDUoazcQ_vHljstyuE","priv":"21kawgH1yBwDLSf4yh63A_AdAja4hh-Q5h_ob_LF-VE","epub":"Z-IWo4zkzXyEL5hWCmvQLY8aoxupbZmJZmKFMDhNJ0U.hoNigMrVpc2npPR17tjOyZchJKk1D8wlQKPCIKZNF_w","epriv":"UUO2sHWG1lrQLNr0t9ObSEHyiasCc_D2HdJS-Vw2FmI"}'
Done in 0.77s.
APP_KEY_PAIR
APP_KEY_PAIR='{"pub":"B14...","priv":"21k...","epub":"Z-I...","epriv":"UUO..."}'
总结
密钥类型功能对比表
密钥类型 | 作用 | 使用场景 | 是否公开 | 说明 |
---|
pub | 身份验证、消息签名验证 | 用于验证签名和公开身份 | 可以公开 | 用于确认数据是否由密钥对的拥有者签名。 |
priv | 消息签名 | 签署消息、身份认证 | 不可公开 | pub 的配对私钥,用于对消息签名;一旦泄露可能导致身份伪造。 |
epub | 数据加密、公钥加密 | 安全数据传输、密钥交换 | 可以公开 | 用于加密数据,与 epriv 配对;确保对称密钥安全共享。 |
epriv | 数据解密 | 解密接收到的加密数据 | 不可公开 | epub 的配对私钥,用于解密加密的数据;必须严格保密。 |
使用示例
epub
/ epriv
用于 数据加密 和 解密。假设已经在 .env
文件中保存了密钥对:
APP_KEY_PAIR='{"pub":"B14...","priv":"21k...","epub":"Z-I...","epriv":"UUO..."}'
const SEA = require('gun/sea');
const pair = JSON.parse(process.env.APP_KEY_PAIR);
async function encryptMessage(message, recipientEpub) {
const encrypted = await SEA.encrypt(message, recipientEpub);
return encrypted;
}
async function decryptMessage(encryptedMessage) {
const decrypted = await SEA.decrypt(encryptedMessage, pair.epriv);
return decrypted;
}
const recipientEpub = 'Z-IWo4zkzXyEL5hWCmvQLY8aoxupbZmJZmKFMDhNJ0U.hoNigMrVpc2npPR17tjOyZchJKk1D8wlQKPCIKZNF_w';
const message = 'Hello, secure world!';
encryptMessage(message, recipientEpub).then((encrypted) => {
console.log('Encrypted Message:', encrypted);
decryptMessage(encrypted).then((decrypted) => {
console.log('Decrypted Message:', decrypted);
});
});
server
- 启动服务:通过 Express 和 GUN 创建服务器。
- GUN 实例配置:
- 验证所有进入的 GUN 消息是否带有有效的 JWT。
- 自动将应用本身认证为 GUN 用户,使其可以管理数据。
- API 路由:
/api/certificates
:允许用户获取证书,以限制其对特定数据路径的访问。/api/tokens
:为用户生成 JWT 令牌,用于请求认证。
引入必要的模块
const express = require('express');
const cors = require('cors');
const jwt = require('jsonwebtoken');
let Gun = require('gun');
const SEA = require('gun/sea');
require('bullet-catcher');
初始化 Express 应用和读取配置
require('dotenv').config();
const app = express();
const port = process.env.PORT || 8765;
const APP_KEY_PAIR = JSON.parse(process.env.APP_KEY_PAIR);
const APP_TOKEN_SECRET = process.env.APP_TOKEN_SECRET;
Web 服务配置
app.use(Gun.serve);
const server = app.listen(port, () => {
console.log(`App listening at http://localhost:${port}`);
});
function verifyToken(msg) {
if (msg?.headers?.accessToken) {
try {
jwt.verify(msg.headers.accessToken, APP_TOKEN_SECRET);
return true;
} catch (err) {
const error = new Error('Invalid access token');
if (err.name === 'TokenExpiredError') {
error.expiredAt = err.expiredAt;
}
return error;
}
}
return false;
}
const gun = Gun({
web: server,
isValid: verifyToken,
});
gun.on('out', { get: { '#': { '*': '' } } });
gun.user().auth(APP_KEY_PAIR, ({ err }) => {
if (err) {
console.error(err);
}
});
API 路由
app.use(express.json());
创建授权证书的 API
app.post('/api/certificates', async (req, res) => {
const { username, pub: userPubKey } = req.body;
const policy = [
{ '*': 'profiles', '+': '*' }
];
const expiresAt = Date.now() + 2 * 60 * 60 * 1000;
try {
const certificate = await SEA.certify(
[userPubKey],
policy,
APP_KEY_PAIR,
null,
{
expiry: expiresAt,
block: 'blocked',
}
);
console.log(`Successfully created certificate for ${username}`);
res.status(201).send({ certificate, expires_at: expiresAt });
} catch (err) {
console.error(`Error creating certificate for ${username}:`, err);
res.status(500).send({ error: err.message });
}
});
生成 JWT 令牌的 API
app.post('/api/tokens', async (req, res) => {
const { username, pub } = req.body;
const token = jwt.sign({ username, pub }, APP_TOKEN_SECRET, {
expiresIn: '1h',
});
res.status(201).send({ accessToken: token });
});
测试
- 启动服务器:
node ./server.js
- 使用
curl
或 Postman 测试 /api/certificates
:curl -X POST http://localhost:8765/api/certificates \
-H "Content-Type: application/json" \
-d '{"username": "alice", "pub": "yourUserPubKey"}'
- 测试
/api/tokens
:curl -X POST http://localhost:8765/api/tokens \
-H "Content-Type: application/json" \
-d '{"username": "alice", "pub": "yourUserPubKey"}'
CG
- https://github.com/amark/gun/wiki/SEA.certify#some-examples::Custom personal profiles in a public room