0
点赞
收藏
分享

微信扫一扫

【p2p、分布式,区块链笔记 DAM】GUN/SEA(Security, Encryption, Authorization) 模块genkey

洛茄 2024-11-18 阅读 5

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

  1. 启动服务:通过 Express 和 GUN 创建服务器。
  2. GUN 实例配置
    • 验证所有进入的 GUN 消息是否带有有效的 JWT。
    • 自动将应用本身认证为 GUN 用户,使其可以管理数据。
  3. API 路由
    • /api/certificates:允许用户获取证书,以限制其对特定数据路径的访问。
    • /api/tokens:为用户生成 JWT 令牌,用于请求认证。

引入必要的模块

// 引入必要的模块
const express = require('express');       // 用于创建 HTTP 服务器
const cors = require('cors');             // 处理跨域请求
const jwt = require('jsonwebtoken');      // 用于生成和验证 JSON Web Token (JWT)
let Gun = require('gun');                 // GUN 去中心化数据库
const SEA = require('gun/sea');           // GUN 的加密模块 (SEA)

// 引入 bullet-catcher 模块以增强错误处理
require('bullet-catcher');

初始化 Express 应用和读取配置

// 初始化 Express 应用和读取配置

// 读取环境变量(.env 文件中的配置)
require('dotenv').config();

const app = express();
// 设定端口号,默认为 8765
const port = process.env.PORT || 8765;

// 读取 GUN 密钥对和 JWT 密钥
const APP_KEY_PAIR = JSON.parse(process.env.APP_KEY_PAIR); // GUN 应用密钥对
const APP_TOKEN_SECRET = process.env.APP_TOKEN_SECRET;     // 用于 JWT 的密钥

Web 服务配置

// 允许 GUN 提供其 Web 服务
app.use(Gun.serve);// Gun.serve:允许 GUN 提供 HTTP 服务,从而启用 WebSocket 通信

// 创建 HTTP 服务器并监听端口
const server = app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});

/**
 * 验证 GUN 消息中的 JWT 是否有效
 * @param {Object} msg - GUN 消息对象
 * @returns {Boolean|Error} - 返回 true 如果验证成功,否则返回错误
 */
function verifyToken(msg) {
  // 检查消息头中是否有 accessToken
  if (msg?.headers?.accessToken) {
    try {
      // 验证 accessToken 是否有效
      jwt.verify(msg.headers.accessToken, APP_TOKEN_SECRET);
      return true; // 如果验证通过,则返回 true
    } catch (err) {
      const error = new Error('Invalid access token'); // 如果验证失败,抛出错误

      // 检查是否是 Token 过期错误
      if (err.name === 'TokenExpiredError') {
        // 如果需要,可以在这里实现自动刷新 token 的逻辑
        error.expiredAt = err.expiredAt;
      }

      return error;
    }
  }
  // 如果消息中没有 accessToken,则返回 false
  return false;
}

// 初始化 GUN 实例,启用 JWT 验证
const gun = Gun({
  web: server,     // 使用刚创建的 HTTP 服务器
  isValid: verifyToken, // 验证传入消息的 accessToken
});

// 同步所有数据
gun.on('out', { get: { '#': { '*': '' } } });

/**
 * 将应用本身授权为 GUN 用户
 * 以便应用可以使用 GUN 网络存取数据
 */
gun.user().auth(APP_KEY_PAIR, ({ err }) => {
  if (err) {
    // 如果认证失败,输出错误信息
    console.error(err);
  }
});

API 路由

// 允许 Express 解析 JSON 请求体
app.use(express.json());

// 如果需要允许跨域访问,可以启用 CORS
// app.use(cors());

创建授权证书的 API

/**
 * 创建授权证书的 API 路由 SEA.certify
 * 允许用户获取权限证书,以限制其修改特定数据路径
 */
app.post('/api/certificates', async (req, res) => {
  // 从请求体中获取用户名和用户的公钥
  const { username, pub: userPubKey } = req.body;

  // 定义访问控制策略
  const policy = [
    // 允许用户添加和编辑他们的 profile 数据
    { '*': 'profiles', '+': '*' }
  ];

  // 设置证书的过期时间为 2 小时
  const expiresAt = Date.now() + 2 * 60 * 60 * 1000;

  try {
    // 使用 GUN 的 SEA 模块生成授权证书
    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

/**
 * 生成 JWT 令牌的 API 路由
 * 用户可以通过此路由获取访问令牌
 */
app.post('/api/tokens', async (req, res) => {
  // 从请求体中获取用户名和用户公钥
  const { username, pub } = req.body;

  // 创建 JWT,设置有效期为 1 小时
  const token = jwt.sign({ username, pub }, APP_TOKEN_SECRET, {
    expiresIn: '1h', // 令牌在 1 小时后过期
  });

  // 返回生成的 accessToken
  res.status(201).send({ accessToken: token });
});

测试

  1. 启动服务器:
    node ./server.js
  2. 使用 curl 或 Postman 测试 /api/certificates
    curl -X POST http://localhost:8765/api/certificates \
    -H "Content-Type: application/json" \
    -d '{"username": "alice", "pub": "yourUserPubKey"}'
    
  3. 测试 /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
举报

相关推荐

0 条评论