require('dotenv').config(); const express = require('express'); const cors = require('cors'); const crypto = require('crypto'); const app = express(); const PORT = 3001; app.use(cors()); app.use(express.json()); const METASTUDIO_API_BASE = 'https://metastudio.cn-north-4.myhuaweicloud.com'; const PROJECT_ID = process.env.HUAWEI_PROJECT_ID || 'c67bf5e7d1f84d20a6eefff2c1ee9cd4'; const IAM_TOKEN_URL = 'https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens'; async function getIamToken() { const username = process.env.HUAWEI_USERNAME; const password = process.env.HUAWEI_PASSWORD; const domainName = process.env.HUAWEI_DOMAIN_NAME || domainName; const region = 'cn-north-4'; if (!username || !password || !domainName) { throw new Error('请配置环境变量: HUAWEI_USERNAME, HUAWEI_PASSWORD, HUAWEI_DOMAIN_NAME'); } const requestBody = { "auth": { "identity": { "methods": ["password"], "password": { "user": { "name": username, "password": password, "domain": { "name": domainName } } } }, "scope": { "project": { "name": region } } } }; const response = await fetch(IAM_TOKEN_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody) }); if (!response.ok) { throw new Error(`IAM认证失败: ${response.status}`); } const token = response.headers.get('X-Subject-Token'); return token; } function buildAKSKSignature(method, host, uri, query, date, headers) { const secretKey = process.env.HUAWEI_SECRET_KEY; if (!secretKey) { throw new Error('请配置环境变量: HUAWEI_SECRET_KEY'); } const signingKey = 'sdk-hmac-sha256'; const dateShort = date.toISOString().slice(0, 10).replace(/-/g, ''); const canonicalRequestParts = [ method.toUpperCase(), uri, query || '', `${headers.toLowerCase()}\n${host.toLowerCase()}` ]; const canonicalRequest = canonicalRequestParts.join('\n'); const stringToSign = [ signingKey, date, `${dateShort}/${region}/metastudio/request`, crypto.createHash('sha256').update(canonicalRequest).digest('hex') ].join('\n'); const signature = crypto .createHmac('sha256', secretKey) .update(stringToSign) .digest('base64'); return { signature, stringToSign, dateShort }; } async function createOnceCodeWithAKSK() { const accessKey = process.env.HUAWEI_AK; const secretKey = process.env.HUAWEI_SK; const region = 'cn-north-4'; if (!accessKey || !secretKey) { throw new Error('请配置环境变量: HUAWEI_AK 和 HUAWEI_SK'); } const host = 'metastudio.cn-north-4.myhuaweicloud.com'; const uri = `/v1/${PROJECT_ID}/digital-human-chat/once-code`; const method = 'POST'; const date = new Date().toUTCString(); const query = ''; const { signature, stringToSign, dateShort } = buildAKSKSignature( method, host, uri, query, date, '' ); const authHeader = `SDK-HMAC-SHA256 Access=${accessKey}, SignedHeaders=host;x-sdk-date, Signature=${signature}`; const response = await fetch(`${METASTUDIO_API_BASE}${uri}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Sdk-Date': date, 'Authorization': authHeader, 'X-Project-Id': PROJECT_ID }, body: JSON.stringify({}) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`API调用失败: ${response.status} - ${errorText}`); } const data = await response.json(); return data.once_code; } app.post('/api/once-code', async (req, res) => { try { let onceCode; if (process.env.HUAWEI_AK && process.env.HUAWEI_SK) { console.log('使用 AK/SK 认证获取授权码...'); onceCode = await createOnceCodeWithAKSK(); } else if (process.env.HUAWEI_USERNAME && process.env.HUAWEI_PASSWORD) { console.log('使用 Token 认证获取授权码...'); const token = await getIamToken(); const response = await fetch( `${METASTUDIO_API_BASE}/v1/${PROJECT_ID}/digital-human-chat/once-code`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Auth-Token': token, 'X-Project-Id': PROJECT_ID }, body: JSON.stringify({}) } ); if (!response.ok) { const errorText = await response.text(); throw new Error(`API调用失败: ${response.status} - ${errorText}`); } const data = await response.json(); onceCode = data.once_code; } else { return res.status(400).json({ error_code: 'CONFIG_MISSING', error_msg: '请配置环境变量 (AK/SK 或用户名密码)' }); } res.json({ once_code: onceCode }); } catch (error) { console.error('获取授权码失败:', error); res.status(500).json({ error_code: 'INTERNAL_ERROR', error_msg: error.message }); } }); app.get('/health', (req, res) => { res.json({ status: 'ok' }); }); app.listen(PORT, () => { console.log(`后端服务已启动: http://localhost:${PORT}`); console.log('支持的认证方式:'); console.log(' 1. AK/SK 认证: 设置 HUAWEI_AK 和 HUAWEI_SK'); console.log(' 2. Token 认证: 设置 HUAWEI_USERNAME, HUAWEI_PASSWORD, HUAWEI_DOMAIN_NAME'); });