Skip to content
/ iyuunet Public

IYUU.net 是一个使用 go 语言开发的高性能代理服务器,通过将 HTTP/JSON-RPC 请求桥接到中国电子口岸 UKey 硬件,提供 179加签、CEB报文加签、身份验证、请求跟踪 和 Webhook通知。

Notifications You must be signed in to change notification settings

ledccn/iyuunet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

China E-Port UKey Proxy Server

A high-performance Go proxy server that bridges HTTP/JSON-RPC requests to China E-Port UKey hardware via WebSocket, providing authentication, request tracking, and webhook notifications.

Features

  • Persistent WebSocket Connection: Maintains a stable connection to UKey hardware with automatic reconnection
  • Request Authentication: MD5-based signature validation for incoming requests
  • Request Tracking: UUID v4 request IDs for complete request/response tracing
  • Webhook Notifications:
    • Failure notifications for UKey malfunctions
    • Audit logging for all requests and responses
  • Health Monitoring: Automatic health checks every 30 seconds
  • Password Management: Automatic password injection from configuration
  • Verbose Logging: Detailed debug logging with password masking

Installation

Prerequisites

  • Go 1.21 or higher
  • UKey hardware accessible via WebSocket

Build

Using Make:

make build           # Build the binary
make build-all       # Build for all platforms (Linux, Windows, macOS)
make install         # Install to $GOPATH/bin

Manual build:

go mod download
go build -o chinaport-proxy

Configuration

Create a config.json file:

{
  "server": {
    "port": "8780"
  },
  "ukey": {
    "url": "ws://127.0.0.1:61232",
    "password": "88888888"
  },
  "auth": {
    "app_secret": "your-secret-key"
  },
  "webhook": {
    "failure_url": "https://your-webhook.com/failure",
    "audit_url": "https://your-webhook.com/audit"
  },
  "log": {
    "verbose": false
  }
}

Configuration Options

Field Description Default
server.port HTTP server port 8780
ukey.url UKey WebSocket URL ws://127.0.0.1:61232
ukey.password UKey password (auto-injected) 88888888
auth.app_secret Secret for signature validation (empty = disabled) -
webhook.failure_url URL for failure notifications -
webhook.audit_url URL for audit logging -
log.verbose Enable debug logging false

Usage

Starting the Server

Using Make:

make run                          # Build and run with default config.json
CONFIG=prod.json make run-config  # Build and run with custom config file
make dev                          # Run with race detector (development)

Direct execution:

# With default config.json
./chinaport-proxy

# With custom config file
./chinaport-proxy -config /path/to/config.json

API Endpoint

The server exposes a single RPC endpoint:

POST /rpc

Request Format

For methods without parameters:

{
  "_method": "cus-sec_SpcGetCertNo"
}

For methods with parameters:

{
  "_method": "cus-sec_SpcSignDataAsPEM",
  "args": {
    "inData": "Hello World"
  }
}

Note:

  • The passwd field is automatically injected from configuration and should not be sent by clients
  • The args field can be omitted for methods that don't require parameters

Response Format

Success response:

{
  "_method": "cus-sec_SpcGetCertNo",
  "_status": "00",
  "_args": {
    "Result": true,
    "Data": ["0177f045"],
    "Error": []
  }
}

Error response (UKey operation failed):

{
  "_method": "cus-sec_SpcSignDataAsPEM",
  "_status": "00",
  "_args": {
    "Result": false,
    "Data": [],
    "Error": ["参数检查失败,传入的args中必须包含必要的非空白参数:inData", "Err:Base50000"]
  }
}

Note: The _status field indicates the protocol status ("00" = success), while _args.Result indicates whether the UKey operation succeeded.

Supported Methods

  • cus-sec_SpcGetCertNo - Get certificate number (no args required)
  • cus-sec_SpcGetEntName - Get enterprise name (no args required)
  • cus-sec_SpcGetEnvCertAsPEM - Get envelope certificate as PEM
  • cus-sec_SpcGetSignCertAsPEM - Get signing certificate as PEM
  • cus-sec_SpcSHA1DigestAsPEM - Calculate SHA1 digest (requires szInfo)
  • cus-sec_SpcSignDataAsPEM - Sign data with hash (requires inData)
  • cus-sec_SpcSignDataNoHashAsPEM - Sign data without hash (requires inData)

Example API Calls

Get enterprise name:

curl -H "Content-Type: application/json" \
  -d '{"_method":"cus-sec_SpcGetEntName"}' \
  http://127.0.0.1:8780/rpc

Get certificate number:

curl -H "Content-Type: application/json" \
  -d '{"_method":"cus-sec_SpcGetCertNo"}' \
  http://127.0.0.1:8780/rpc

Sign data:

curl -H "Content-Type: application/json" \
  -d '{"_method":"cus-sec_SpcSignDataAsPEM","args":{"inData":"Hello World"}}' \
  http://127.0.0.1:8780/rpc

Customs 179 Data Upload

Example request with nested JSON objects (no stringified sub-fields):

curl -X POST http://localhost:8780/api/customs179 \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "123456",
    "payExchangeInfoHead": {"guid":"IYUU4A6D0D78893C739E004DA89918FC8DBB","initalRequest":"<xml><openid><![CDATA[o9dVx7XBtxqRvfQEuaUkoSFiHdto]]></openid><out_trade_no><![CDATA[cp477912536700682240]]></out_trade_no><total_fee>14364</total_fee><attach><![CDATA[product]]></attach><body><![CDATA[ISG--ISG BioSkin 赋活奇....]]></body><trade_type><![CDATA[JSAPI]]></trade_type><notify_url><![CDATA[https://isg.tw.cn/api/pay/notify/routine]]></notify_url><spbill_create_ip><![CDATA[27.148.85.253]]></spbill_create_ip><appid><![CDATA[wxff7ddeae4a59f857]]></appid><mch_id>1695916432</mch_id><nonce_str><![CDATA[6899cbbe0592c]]></nonce_str><sign><![CDATA[CA932F8245FBC44195A2C89B98039F9A]]></sign></xml>","initalResponse":"ok","ebpCode":"3506960ABA","payCode":"4403169D3W","payTransactionId":"4200002754202508110844258623","totalAmount":143.64,"currency":"142","verDept":"3","payType":"4","tradingTime":"20250811185359","note":"备注"},
    "payExchangeInfoLists": [{"orderNo":"cp477912536700681230","goodsInfo":[{"gname":"ISG BioSkin 赋活奇肌全方位洗卸慕斯150mL","itemLink":"https://isg.tw.cn/pages/goods_details/index?id=8"}],"recpAccount":"612755288","recpCode":"91350603MADY5YXCX2","recpName":"漳州伊诗嘉跨境电子商务有限公司"}],
    "serviceTime": 1756571640000,
    "realTimeDataUpload": true
  }'

Authentication

When auth.app_secret is configured, all requests must include authentication headers:

Required Headers

  • X-Timestamp: Current timestamp in milliseconds
  • X-Signature: MD5 signature of the request

Signature Algorithm

signature = MD5(METHOD + PATH + TIMESTAMP + BODY + APP_SECRET)

Where:

  • METHOD: HTTP method in uppercase (e.g., "POST")
  • PATH: Request path (e.g., "/rpc")
  • TIMESTAMP: Same as X-Timestamp header
  • BODY: Raw request body
  • APP_SECRET: Configured secret key

Timestamp Validation

Requests must be within 3 seconds of server time to prevent replay attacks.

Example (Node.js)

const crypto = require('crypto');

function makeAuthenticatedRequest(body) {
  const timestamp = Date.now();
  const method = 'POST';
  const path = '/rpc';
  const appSecret = 'your-secret-key';
  
  const plaintext = method + path + timestamp + JSON.stringify(body) + appSecret;
  const signature = crypto.createHash('md5').update(plaintext).digest('hex');
  
  return fetch('http://localhost:8780/rpc', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Timestamp': timestamp.toString(),
      'X-Signature': signature
    },
    body: JSON.stringify(body)
  });
}

Request Tracking

Every request is assigned a UUID v4 request ID for tracing:

  • Request ID is returned in the X-Request-ID response header
  • All logs related to the request include this ID
  • Request ID is included in webhook notifications

Webhooks

Failure Webhook

Triggered when UKey operations fail or connection issues occur.

Payload:

{
  "event": "ukey_malfunction",
  "timestamp": 1723809415000,
  "error": "Error description",
  "details": {
    "type": "operation_failure",
    "method": "cus-sec_SpcGetCertNo",
    "errors": ["error1", "error2"]
  }
}

Failure types:

  • operation_failure: UKey method execution failed
  • connection_failure: WebSocket connection lost
  • health_check_failure: Health check failed

Audit Webhook

Triggered for all requests (success or failure) for auditing purposes.

Payload:

{
  "event": "api_audit",
  "timestamp": 1723809415000,
  "request_id": "uuid-here",
  "method": "cus-sec_SpcGetCertNo",
  "request": {},
  "response": {},
  "success": true,
  "error": "",
  "duration_ms": 125
}

Webhook Authentication

Webhooks use the same authentication mechanism as incoming requests:

  • X-Timestamp header with current timestamp
  • X-Signature header with MD5 signature

Verifying Webhook Signatures

To verify webhooks are from the proxy server, implement the same signature validation:

// Node.js example
const crypto = require('crypto');

function verifyWebhookSignature(req, appSecret) {
  const timestamp = req.headers['x-timestamp'];
  const signature = req.headers['x-signature'];
  const method = req.method;
  const path = req.path; // e.g., '/webhook/audit'
  const body = req.rawBody; // Raw request body string
  
  // Check timestamp (within 3 seconds)
  const now = Date.now();
  const timeDiff = Math.abs(now - parseInt(timestamp));
  if (timeDiff > 3000) {
    return false; // Timestamp expired
  }
  
  // Calculate expected signature
  const plaintext = method.toUpperCase() + path + timestamp + body + appSecret;
  const expectedSignature = crypto.createHash('md5').update(plaintext).digest('hex');
  
  return expectedSignature === signature;
}

// Express.js middleware example
app.use(express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
}));

app.post('/webhook/audit', (req, res) => {
  if (!verifyWebhookSignature(req, 'your-secret-key')) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Process webhook
  console.log('Audit event:', req.body);
  res.json({ status: 'received' });
});

Health Monitoring

The server performs automatic health checks:

  • Interval: 30 seconds
  • Method: Calls cus-sec_SpcGetCertNo to verify UKey connectivity
  • On failure: Triggers reconnection and sends failure webhook

Logging

Log Levels

  • Normal mode: INFO level and above
  • Verbose mode: DEBUG level with detailed request/response logging

Password Masking

All passwords in logs are automatically masked as ***MASKED*** for security.

Log Examples

2024/01/15 10:30:00 INFO Starting China E-Port proxy server address=:8780
2024/01/15 10:30:01 INFO WebSocket connected
2024/01/15 10:30:15 INFO Received RPC request method=cus-sec_SpcGetCertNo request_id=abc-123
2024/01/15 10:30:15 INFO Request completed successfully method=cus-sec_SpcGetCertNo request_id=abc-123

Error Handling

HTTP Status Codes

  • 200 OK: Successful UKey operation
  • 400 Bad Request: UKey operation failed or invalid request format
  • 401 Unauthorized: Authentication failed
  • 503 Service Unavailable: UKey connection issues

Automatic Reconnection

  • Exponential backoff starting at 1 second
  • Maximum backoff: 8 seconds
  • Continues indefinitely until connection restored

Signal Handling

The server handles SIGTERM and SIGINT signals:

  1. Stops accepting new requests
  2. Waits for active requests to complete (up to 10 seconds)
  3. Closes WebSocket connection
  4. Exits cleanly

Development

Project Structure

chinaport-proxy/
├── main.go                 # Application entry point
├── config.json             # Configuration file
├── go.mod                  # Go module definition
├── config/
│   └── config.go          # Configuration structures
├── client/
│   └── ukey.go            # WebSocket client implementation
├── handlers/
│   └── proxy.go           # HTTP request handlers
├── services/
│   └── webhook.go         # Webhook service
├── middleware/
│   └── auth.go            # Authentication middleware
├── auth/
│   └── signature.go       # Signature generation/validation
├── protocol/
│   └── types.go           # Protocol type definitions
└── utils/
    └── logging.go         # Logging utilities

Code Quality

Using Make:

make fmt                   # Format code
make vet                   # Vet code  
make check                 # Run fmt and vet

Building for Production

Using Make:

make build-linux      # Linux (amd64, arm64)
make build-windows    # Windows (amd64)
make build-darwin     # macOS (amd64, arm64)
make build-all        # All platforms

Manual cross-compilation:

# Linux
GOOS=linux GOARCH=amd64 go build -o chinaport-proxy

# Windows
GOOS=windows GOARCH=amd64 go build -o chinaport-proxy.exe

Other Make Commands

make clean            # Remove build artifacts
make fmt              # Format code
make vet              # Vet code
make deps             # Download dependencies
make tidy             # Tidy dependencies

About

IYUU.net 是一个使用 go 语言开发的高性能代理服务器,通过将 HTTP/JSON-RPC 请求桥接到中国电子口岸 UKey 硬件,提供 179加签、CEB报文加签、身份验证、请求跟踪 和 Webhook通知。

Resources

Stars

Watchers

Forks

Packages

No packages published