|
@@ -0,0 +1,153 @@
|
|
|
|
|
+import { GetNumberResponse, GetNumberService } from './get-number-service'
|
|
|
|
|
+import { RcsNumberSource } from '../entities/rcs-number.entity'
|
|
|
|
|
+import { InternalServerErrorException, BadRequestException } from '@nestjs/common'
|
|
|
|
|
+import axios, { AxiosError } from 'axios'
|
|
|
|
|
+import { createHash } from 'node:crypto'
|
|
|
|
|
+import * as querystring from 'node:querystring'
|
|
|
|
|
+
|
|
|
|
|
+const axiosInstance = axios.create({
|
|
|
|
|
+ baseURL: 'http://api.xlcode.io'
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const cid = '2940177066730633'
|
|
|
|
|
+const appId = '9'
|
|
|
|
|
+const key = 'K3oo52i13ebkm4smd75p1v5pzq8h2nsf'
|
|
|
|
|
+
|
|
|
|
|
+export class xlcode extends GetNumberService {
|
|
|
|
|
+ source: RcsNumberSource = RcsNumberSource.xlcode
|
|
|
|
|
+
|
|
|
|
|
+ private generateSign(params: Record<string, string>): string {
|
|
|
|
|
+ // 按字典序排序参数
|
|
|
|
|
+ const sortedParams = Object.keys(params)
|
|
|
|
|
+ .sort()
|
|
|
|
|
+ .reduce((acc, key) => {
|
|
|
|
|
+ acc[key] = params[key]
|
|
|
|
|
+ return acc
|
|
|
|
|
+ }, {})
|
|
|
|
|
+
|
|
|
|
|
+ // 构建签名字符串
|
|
|
|
|
+ let signStr = Object.entries(sortedParams)
|
|
|
|
|
+ .map(([key, value]) => `${key}=${value}`)
|
|
|
|
|
+ .join('&')
|
|
|
|
|
+ signStr += `&key=${key}`
|
|
|
|
|
+
|
|
|
|
|
+ // 计算MD5并转换为大写
|
|
|
|
|
+ return createHash('md5').update(signStr).digest('hex').toUpperCase()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async getNumber(country: string, num?: number): Promise<GetNumberResponse> {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ cid,
|
|
|
|
|
+ appId,
|
|
|
|
|
+ attr: country.toUpperCase()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const sign = this.generateSign(params)
|
|
|
|
|
+ const formData = querystring.stringify({
|
|
|
|
|
+ ...params,
|
|
|
|
|
+ sign
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await axiosInstance.post('/api/account', formData, {
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ if (res.data.code !== 0) {
|
|
|
|
|
+ throw new InternalServerErrorException(res.data.msg)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ number: res.data.data.account,
|
|
|
|
|
+ orderId: res.data.data.id,
|
|
|
|
|
+ operatorCode: res.data.data.countryCode || '',
|
|
|
|
|
+ operatorName: res.data.data.regionCode || '',
|
|
|
|
|
+ rawResponse: res.data
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ if (error instanceof AxiosError && error.response?.status === 400) {
|
|
|
|
|
+ const errorData = error.response.data
|
|
|
|
|
+ throw new BadRequestException('xlcode error: ' + errorData.msg || '请求参数错误')
|
|
|
|
|
+ }
|
|
|
|
|
+ throw error
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async retriveMessage(orderId: string, num?: number): Promise<string> {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ cid,
|
|
|
|
|
+ id: orderId
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const sign = this.generateSign(params)
|
|
|
|
|
+ const formData = querystring.stringify({
|
|
|
|
|
+ ...params,
|
|
|
|
|
+ sign
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await axiosInstance.post('/api/code', formData, {
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ console.log(res.data)
|
|
|
|
|
+
|
|
|
|
|
+ if (res.data.code !== 0) {
|
|
|
|
|
+ throw new InternalServerErrorException(res.data.msg)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (res.data.data.code) {
|
|
|
|
|
+ return res.data.data.content || `Your Messenger verification code is G-${res.data.data.code}`
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ if (error instanceof AxiosError && error.response?.status === 400) {
|
|
|
|
|
+ const errorData = error.response.data
|
|
|
|
|
+ throw new BadRequestException(errorData.msg || '请求参数错误')
|
|
|
|
|
+ }
|
|
|
|
|
+ throw error
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async releaseNumber(number: string): Promise<void> {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ cid,
|
|
|
|
|
+ id: number
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const sign = this.generateSign(params)
|
|
|
|
|
+ const formData = querystring.stringify({
|
|
|
|
|
+ ...params,
|
|
|
|
|
+ sign
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await axiosInstance.post('/api/release', formData, {
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ if (res.data.code !== 0) {
|
|
|
|
|
+ throw new InternalServerErrorException(res.data.msg)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ if (error instanceof AxiosError && error.response?.status === 400) {
|
|
|
|
|
+ const errorData = error.response.data
|
|
|
|
|
+ throw new BadRequestException(errorData.msg || '请求参数错误')
|
|
|
|
|
+ }
|
|
|
|
|
+ throw error
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async blockNumber(number: string): Promise<void> {}
|
|
|
|
|
+
|
|
|
|
|
+ async cacheNumber(country: string, size: number): Promise<GetNumberResponse[]> {
|
|
|
|
|
+ return null
|
|
|
|
|
+ }
|
|
|
|
|
+}
|