92 lines
3.3 KiB
TypeScript
92 lines
3.3 KiB
TypeScript
import crypto from 'node:crypto'
|
||
import https from 'node:https'
|
||
|
||
import { runtimeConfig } from '../src/config/runtime.js'
|
||
|
||
function percentEncode(value: string): string {
|
||
return encodeURIComponent(String(value || ''))
|
||
.replace(/\+/g, '%20')
|
||
.replace(/\*/g, '%2A')
|
||
.replace(/%7E/g, '~')
|
||
}
|
||
|
||
function signAliyunRequest(params: Record<string, string>, accessKeySecret: string): string {
|
||
const canonicalizedQuery = Object.entries(params)
|
||
.map(([key, value]) => `${percentEncode(key)}=${percentEncode(value)}`)
|
||
.sort((left, right) =>
|
||
String(left[0]) < String(right[0]) ? -1 : String(left[0]) > String(right[0]) ? 1 : 0,
|
||
)
|
||
.join('&')
|
||
const stringToSign = `GET&${percentEncode('/')}&${percentEncode(canonicalizedQuery)}`
|
||
const hmac = crypto.createHmac('sha1', `${accessKeySecret}&`)
|
||
hmac.update(stringToSign)
|
||
return hmac.digest('base64')
|
||
}
|
||
|
||
async function main() {
|
||
const config = runtimeConfig.worker.sms
|
||
console.log('当前短信配置:')
|
||
console.log(' provider :', config.provider)
|
||
console.log(' accessKeyId :', config.accessKeyId ? `${config.accessKeyId.slice(0, 4)}...${config.accessKeyId.slice(-4)}` : '(空)')
|
||
console.log(' accessKeySecret :', config.accessKeySecret ? `${config.accessKeySecret.slice(0, 4)}...${config.accessKeySecret.slice(-4)}(长度 ${config.accessKeySecret.length})` : '(空)')
|
||
console.log(' signName :', config.signName)
|
||
console.log(' templateCode :', config.templateCode)
|
||
console.log('')
|
||
|
||
if (!config.accessKeyId || !config.accessKeySecret || !config.signName || !config.templateCode) {
|
||
console.error('配置不完整,请检查 .env 中的 WORKER_SMS_* 配置')
|
||
return
|
||
}
|
||
|
||
const phone = process.argv[2] || '13800000000'
|
||
const params: Record<string, string> = {
|
||
AccessKeyId: config.accessKeyId,
|
||
Action: 'SendSms',
|
||
Format: 'JSON',
|
||
Version: '2017-05-25',
|
||
SignatureMethod: 'HMAC-SHA1',
|
||
SignatureVersion: '1.0',
|
||
SignatureNonce: crypto.randomUUID(),
|
||
Timestamp: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'),
|
||
PhoneNumbers: phone,
|
||
SignName: config.signName,
|
||
TemplateCode: config.templateCode,
|
||
TemplateParam: JSON.stringify({ code: '123456' }),
|
||
}
|
||
|
||
const signature = signAliyunRequest(params, config.accessKeySecret)
|
||
params.Signature = signature
|
||
|
||
const queryString = Object.entries(params)
|
||
.map(([key, value]) => `${percentEncode(key)}=${percentEncode(value)}`)
|
||
.sort()
|
||
.join('&')
|
||
const url = `https://dysmsapi.aliyuncs.com/?${queryString}`
|
||
|
||
console.log('stringToSign:')
|
||
console.log(' ', `GET&%2F&${percentEncode(
|
||
Object.entries(params)
|
||
.filter(([key]) => key !== 'Signature')
|
||
.map(([key, value]) => `${percentEncode(key)}=${percentEncode(value)}`)
|
||
.sort((left, right) => (String(left[0]) < String(right[0]) ? -1 : String(left[0]) > String(right[0]) ? 1 : 0))
|
||
.join('&'),
|
||
)}`)
|
||
console.log('')
|
||
console.log(`发送测试短信到 ${phone}(验证码 123456)...`)
|
||
|
||
https
|
||
.get(url, (response) => {
|
||
const chunks: Buffer[] = []
|
||
response.on('data', (chunk) => chunks.push(Buffer.from(chunk)))
|
||
response.on('end', () => {
|
||
const body = Buffer.concat(chunks).toString('utf8')
|
||
console.log('响应:', body)
|
||
})
|
||
})
|
||
.on('error', (error) => {
|
||
console.error('请求失败:', error.message)
|
||
})
|
||
}
|
||
|
||
void main()
|