mirror of https://github.com/certd/certd
refactor: dnspod支持
parent
49b96592a0
commit
71f6d5769a
|
@ -12,9 +12,12 @@
|
|||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@types/node": "^14.14.13",
|
||||
"axios": "^0.21.1",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash": "^4.17.20",
|
||||
"log4js": "^6.3.0",
|
||||
"node-forge": "^0.10.0",
|
||||
"qs": "^6.9.4",
|
||||
"@certd/acme-client": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,47 +1,58 @@
|
|||
import log from './utils/util.log.js'
|
||||
import acme from '@certd/acme-client'
|
||||
import _ from 'lodash'
|
||||
import path from 'path'
|
||||
import sleep from './utils/util.sleep.js'
|
||||
export class AcmeService {
|
||||
constructor (store) {
|
||||
this.store = store
|
||||
}
|
||||
|
||||
async getAccountKey (email) {
|
||||
let key = this.store.get(this.buildAccountKeyPath(email))
|
||||
if (key == null) {
|
||||
key = await this.createNewKey({ email })
|
||||
async getAccountConfig (email) {
|
||||
let conf = this.store.get(this.buildAccountPath(email))
|
||||
if (conf == null) {
|
||||
conf = {}
|
||||
} else {
|
||||
conf = JSON.parse(conf)
|
||||
}
|
||||
return key
|
||||
return conf
|
||||
}
|
||||
|
||||
buildAccountKeyPath (email) {
|
||||
return email + '/acme/account.key'
|
||||
buildAccountPath (email) {
|
||||
return path.join(email, '/account.json')
|
||||
}
|
||||
|
||||
setAccountKey (email, privateKey) {
|
||||
this.store.set(this.buildAccountKeyPath(email), privateKey)
|
||||
saveAccountConfig (email, conf) {
|
||||
this.store.set(this.buildAccountPath(email), JSON.stringify(conf))
|
||||
}
|
||||
|
||||
async getAcmeClient (email) {
|
||||
const key = await this.getAccountKey(email)
|
||||
const conf = await this.getAccountConfig(email)
|
||||
if (conf.key == null) {
|
||||
conf.key = await this.createNewKey()
|
||||
this.saveAccountConfig(email, conf)
|
||||
}
|
||||
const client = new acme.Client({
|
||||
directoryUrl: acme.directory.letsencrypt.staging,
|
||||
accountKey: key,
|
||||
backoffAttempts: 10,
|
||||
accountKey: conf.key,
|
||||
accountUrl: conf.accountUrl,
|
||||
backoffAttempts: 20,
|
||||
backoffMin: 5000,
|
||||
backoffMax: 10000
|
||||
})
|
||||
|
||||
if (conf.accountUrl == null) {
|
||||
const accountPayload = { termsOfServiceAgreed: true, contact: [`mailto:${email}`] }
|
||||
await client.createAccount(accountPayload)
|
||||
conf.accountUrl = client.getAccountUrl()
|
||||
this.saveAccountConfig(email, conf)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
async createNewKey ({ email }) {
|
||||
const privateKey = await acme.forge.createPrivateKey()
|
||||
this.setAccountKey(email, privateKey)
|
||||
}
|
||||
|
||||
async loggerin () {
|
||||
|
||||
async createNewKey () {
|
||||
const key = await acme.forge.createPrivateKey()
|
||||
return key.toString()
|
||||
}
|
||||
|
||||
async challengeCreateFn (authz, challenge, keyAuthorization, dnsProvider) {
|
||||
|
@ -67,7 +78,11 @@ export class AcmeService {
|
|||
/* Replace this */
|
||||
log.info(`Would create TXT record "${dnsRecord}" with value "${recordValue}"`)
|
||||
|
||||
return await dnsProvider.createRecord(dnsRecord, 'TXT', recordValue)
|
||||
return await dnsProvider.createRecord({
|
||||
fullRecord: dnsRecord,
|
||||
type: 'TXT',
|
||||
value: recordValue
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,10 +92,12 @@ export class AcmeService {
|
|||
* @param {object} authz Authorization object
|
||||
* @param {object} challenge Selected challenge
|
||||
* @param {string} keyAuthorization Authorization key
|
||||
* @param recordItem challengeCreateFn create record item
|
||||
* @param dnsProvider dnsProvider
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
async challengeRemoveFn (authz, challenge, keyAuthorization, dnsProvider) {
|
||||
async challengeRemoveFn (authz, challenge, keyAuthorization, recordItem, dnsProvider) {
|
||||
log.info('Triggered challengeRemoveFn()')
|
||||
|
||||
/* http-01 */
|
||||
|
@ -100,12 +117,24 @@ export class AcmeService {
|
|||
|
||||
/* Replace this */
|
||||
log.info(`Would remove TXT record "${dnsRecord}" with value "${recordValue}"`)
|
||||
await dnsProvider.removeRecord(dnsRecord, 'TXT', keyAuthorization)
|
||||
await dnsProvider.removeRecord({
|
||||
fullRecord: dnsRecord,
|
||||
type: 'TXT',
|
||||
value: keyAuthorization,
|
||||
record: recordItem
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async order ({ email, domains, dnsProvider, dnsProviderCreator, csrInfo }) {
|
||||
const client = await this.getAcmeClient(email)
|
||||
|
||||
let accountUrl
|
||||
try {
|
||||
accountUrl = client.getAccountUrl()
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
/* Create CSR */
|
||||
const { commonName, altNames } = this.buildCommonNameByDomains(domains)
|
||||
|
||||
|
@ -120,7 +149,7 @@ export class AcmeService {
|
|||
if (dnsProvider == null) {
|
||||
throw new Error('dnsProvider 不能为空')
|
||||
}
|
||||
/* Certificate */
|
||||
/* 自动申请证书 */
|
||||
const crt = await client.auto({
|
||||
csr,
|
||||
email: email,
|
||||
|
@ -129,11 +158,20 @@ export class AcmeService {
|
|||
challengeCreateFn: async (authz, challenge, keyAuthorization) => {
|
||||
return await this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider)
|
||||
},
|
||||
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
|
||||
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, dnsProvider)
|
||||
challengeRemoveFn: async (authz, challenge, keyAuthorization, recordItem) => {
|
||||
return await this.challengeRemoveFn(authz, challenge, keyAuthorization, recordItem, dnsProvider)
|
||||
}
|
||||
})
|
||||
|
||||
// 保存账号url
|
||||
if (!accountUrl) {
|
||||
try {
|
||||
accountUrl = client.getAccountUrl()
|
||||
this.setAccountUrl(email, accountUrl)
|
||||
} catch (e) {
|
||||
log.warn('保存accountUrl出错', e)
|
||||
}
|
||||
}
|
||||
/* Done */
|
||||
log.debug(`CSR:\n${csr.toString()}`)
|
||||
log.debug(`Certificate:\n${crt.toString()}`)
|
||||
|
|
|
@ -1,9 +1,29 @@
|
|||
import _ from 'lodash'
|
||||
export class DnsProvider {
|
||||
createRecord (dnsRecord, type, recordValue) {
|
||||
|
||||
async createRecord ({ fullRecord, type, value }) {
|
||||
throw new Error('请实现 createRecord 方法')
|
||||
}
|
||||
|
||||
removeRecord (dnsRecord, type, recordValue) {
|
||||
async removeRecord ({ fullRecord, type, value, record }) {
|
||||
throw new Error('请实现 removeRecord 方法')
|
||||
}
|
||||
|
||||
async getDomainList () {
|
||||
throw new Error('请实现 getDomainList 方法')
|
||||
}
|
||||
|
||||
async matchDomain (dnsRecord, domainPropName) {
|
||||
const list = await this.getDomainList()
|
||||
let domain = null
|
||||
for (const item of list) {
|
||||
if (_.endsWith(dnsRecord, item[domainPropName])) {
|
||||
domain = item
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!domain) {
|
||||
throw new Error('找不到域名,请检查域名是否正确:' + dnsRecord)
|
||||
}
|
||||
return domain
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,17 +59,18 @@ export default class AliyunDnsProvider extends DnsProvider {
|
|||
return ret.DomainRecords.Record
|
||||
}
|
||||
|
||||
async createRecord (dnsRecord, type, recordValue) {
|
||||
log.info('添加域名解析:', dnsRecord, recordValue)
|
||||
const domain = await this.matchDomain(dnsRecord)
|
||||
const rr = dnsRecord.replace('.' + domain, '')
|
||||
async createRecord ({ fullRecord, type, value }) {
|
||||
log.info('添加域名解析:', fullRecord, value)
|
||||
const domain = await this.matchDomain(fullRecord)
|
||||
const rr = fullRecord.replace('.' + domain, '')
|
||||
|
||||
const params = {
|
||||
RegionId: 'cn-hangzhou',
|
||||
DomainName: domain,
|
||||
RR: rr,
|
||||
Type: type,
|
||||
Value: recordValue
|
||||
Value: value,
|
||||
Line: 'oversea' // 海外
|
||||
}
|
||||
|
||||
const requestOption = {
|
||||
|
@ -78,7 +79,7 @@ export default class AliyunDnsProvider extends DnsProvider {
|
|||
|
||||
try {
|
||||
const ret = await this.client.request('AddDomainRecord', params, requestOption)
|
||||
console.log('添加域名解析成功:', dnsRecord, recordValue, ret.RecordId)
|
||||
console.log('添加域名解析成功:', value, value, ret.RecordId)
|
||||
return ret.RecordId
|
||||
} catch (e) {
|
||||
// e.code === 'DomainRecordDuplicate'
|
||||
|
@ -87,15 +88,10 @@ export default class AliyunDnsProvider extends DnsProvider {
|
|||
}
|
||||
}
|
||||
|
||||
async removeRecord (dnsRecord, type, value) {
|
||||
const domain = await this.matchDomain(dnsRecord)
|
||||
const rr = dnsRecord.replace('.' + domain, '')
|
||||
|
||||
const record = await this.getRecords(domain, rr, value)
|
||||
|
||||
async removeRecord ({ fullRecord, type, value, record }) {
|
||||
const params = {
|
||||
RegionId: 'cn-hangzhou',
|
||||
RecordId: record[0].RecordId
|
||||
RecordId: record
|
||||
}
|
||||
|
||||
const requestOption = {
|
||||
|
@ -103,7 +99,7 @@ export default class AliyunDnsProvider extends DnsProvider {
|
|||
}
|
||||
|
||||
const ret = await this.client.request('DeleteDomainRecord', params, requestOption)
|
||||
log.info('删除域名解析成功:', dnsRecord, value, ret.RecordId)
|
||||
log.info('删除域名解析成功:', fullRecord, value, ret.RecordId)
|
||||
return ret.RecordId
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import { DnsProvider } from '../dns-provider.js'
|
||||
import _ from 'lodash'
|
||||
import log from '../../utils/util.log.js'
|
||||
import { request } from '../../utils/util.request.js'
|
||||
export default class DnspodDnsProvider extends DnsProvider {
|
||||
constructor (dnsProviderConfig) {
|
||||
super()
|
||||
if (!dnsProviderConfig.id || !dnsProviderConfig.token) {
|
||||
throw new Error('请正确配置dnspod的 id 和 token')
|
||||
}
|
||||
this.loginToken = dnsProviderConfig.id + ',' + dnsProviderConfig.token
|
||||
}
|
||||
|
||||
async doRequest (options) {
|
||||
const config = {
|
||||
method: 'post',
|
||||
formData: {
|
||||
login_token: this.loginToken,
|
||||
format: 'json',
|
||||
lang: 'cn',
|
||||
error_on_empty: 'no'
|
||||
},
|
||||
timeout: 5000
|
||||
}
|
||||
_.merge(config, options)
|
||||
|
||||
const ret = await request(config)
|
||||
if (ret?.status?.code !== '1') {
|
||||
throw new Error('请求失败:' + ret.status.message + ',api=' + config.url)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
async getDomainList () {
|
||||
const ret = await this.doRequest({
|
||||
url: 'https://dnsapi.cn/Domain.List'
|
||||
})
|
||||
log.debug('dnspod 域名列表:', ret.domains)
|
||||
return ret.domains
|
||||
}
|
||||
|
||||
async createRecord ({ fullRecord, type, value }) {
|
||||
log.info('添加域名解析:', fullRecord, value)
|
||||
const domainItem = await this.matchDomain(fullRecord, 'name')
|
||||
const domain = domainItem.name
|
||||
const rr = fullRecord.replace('.' + domain, '')
|
||||
|
||||
const ret = await this.doRequest({
|
||||
url: 'https://dnsapi.cn/Record.Create',
|
||||
formData: {
|
||||
domain,
|
||||
sub_domain: rr,
|
||||
record_type: type,
|
||||
record_line: '默认',
|
||||
value: value,
|
||||
mx: 1
|
||||
}
|
||||
})
|
||||
console.log('添加域名解析成功:', fullRecord, value, JSON.stringify(ret.record))
|
||||
return ret.record
|
||||
}
|
||||
|
||||
async removeRecord ({ fullRecord, type, value, record }) {
|
||||
const domain = await this.matchDomain(fullRecord, 'name')
|
||||
|
||||
const ret = await this.doRequest({
|
||||
url: 'https://dnsapi.cn/Record.Remove',
|
||||
formData: {
|
||||
domain,
|
||||
record_id: record.id
|
||||
}
|
||||
})
|
||||
log.info('删除域名解析成功:', fullRecord, value)
|
||||
return ret.RecordId
|
||||
}
|
||||
}
|
|
@ -95,7 +95,7 @@ export class Certd {
|
|||
|
||||
async createDnsProvider (options) {
|
||||
const accessProviders = options.accessProviders
|
||||
const providerOptions = accessProviders[options.cert.challenge.dnsProvider]
|
||||
const providerOptions = accessProviders[options.cert.dnsProvider]
|
||||
return await DnsProviderFactory.createByType(providerOptions.providerType, providerOptions)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import axios from 'axios'
|
||||
import log from './util.log.js'
|
||||
import qs from 'qs'
|
||||
/**
|
||||
* @description 创建请求实例
|
||||
*/
|
||||
function createService () {
|
||||
// 创建一个 axios 实例
|
||||
const service = axios.create()
|
||||
// 请求拦截
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
if (config.formData) {
|
||||
config.data = qs.stringify(config.formData, {
|
||||
arrayFormat: 'indices',
|
||||
allowDots: true
|
||||
}) // 序列化请求参数
|
||||
delete config.formData
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// 发送失败
|
||||
log.error(error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
// 响应拦截
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
return response.data
|
||||
},
|
||||
error => {
|
||||
// const status = _.get(error, 'response.status')
|
||||
// switch (status) {
|
||||
// case 400: error.message = '请求错误'; break
|
||||
// case 401: error.message = '未授权,请登录'; break
|
||||
// case 403: error.message = '拒绝访问'; break
|
||||
// case 404: error.message = `请求地址出错: ${error.response.config.url}`; break
|
||||
// case 408: error.message = '请求超时'; break
|
||||
// case 500: error.message = '服务器内部错误'; break
|
||||
// case 501: error.message = '服务未实现'; break
|
||||
// case 502: error.message = '网关错误'; break
|
||||
// case 503: error.message = '服务不可用'; break
|
||||
// case 504: error.message = '网关超时'; break
|
||||
// case 505: error.message = 'HTTP版本不受支持'; break
|
||||
// default: break
|
||||
// }
|
||||
log.error('请求出错:', error.response.config.url, error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
return service
|
||||
}
|
||||
|
||||
export const request = createService()
|
|
@ -1,6 +1,7 @@
|
|||
import pkg from 'chai'
|
||||
import options from '../options.js'
|
||||
import AliyunDnsProvider from '../../src/dns-provider/impl/aliyun.js'
|
||||
import { Certd } from '../../src/index.js'
|
||||
const { expect } = pkg
|
||||
describe('AliyunDnsProvider', function () {
|
||||
it('#getDomainList', async function () {
|
||||
|
@ -17,17 +18,26 @@ describe('AliyunDnsProvider', function () {
|
|||
expect(recordList.length).gt(0)
|
||||
})
|
||||
|
||||
it('#createRecord', async function () {
|
||||
it('#createAndRemoveRecord', async function () {
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options.accessProviders.aliyun)
|
||||
const recordId = await aliyunDnsProvider.createRecord('___certd___.__test__.docmirror.cn', 'TXT', 'aaaa')
|
||||
const record = await aliyunDnsProvider.createRecord({ fullRecord: '___certd___.__test__.docmirror.cn', type: 'TXT', value: 'aaaa' })
|
||||
console.log('recordId', record)
|
||||
expect(record != null).ok
|
||||
|
||||
const recordId = await aliyunDnsProvider.removeRecord({ fullRecord: '___certd___.__test__.docmirror.cn', type: 'TXT', value: 'aaaa', record })
|
||||
console.log('recordId', recordId)
|
||||
expect(recordId != null).ok
|
||||
})
|
||||
|
||||
it('#removeRecord', async function () {
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options.accessProviders.aliyun)
|
||||
const recordId = await aliyunDnsProvider.removeRecord('___certd___.__test__.docmirror.cn', 'TXT', 'aaaa')
|
||||
console.log('recordId', recordId)
|
||||
expect(recordId != null).ok
|
||||
it('#申请证书-aliyun', async function () {
|
||||
this.timeout(300000)
|
||||
options.args = { forceCert: true }
|
||||
const certd = new Certd()
|
||||
const cert = await certd.certApply(options)
|
||||
expect(cert).ok
|
||||
expect(cert.crt).ok
|
||||
expect(cert.key).ok
|
||||
expect(cert.detail).ok
|
||||
expect(cert.expires).ok
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import pkg from 'chai'
|
||||
import options from '../options.js'
|
||||
import DnspodDnsProvider from '../../src/dns-provider/impl/dnspod.js'
|
||||
import { Certd } from '../../src/index.js'
|
||||
const { expect } = pkg
|
||||
describe('DnspodDnsProvider', function () {
|
||||
it('#getDomainList', async function () {
|
||||
const dnsProvider = new DnspodDnsProvider(options.accessProviders.dnspod)
|
||||
const domainList = await dnsProvider.getDomainList()
|
||||
console.log('domainList', domainList)
|
||||
expect(domainList.length).gt(0)
|
||||
})
|
||||
|
||||
it('#createRecord&removeRecord', async function () {
|
||||
const dnsProvider = new DnspodDnsProvider(options.accessProviders.dnspod)
|
||||
const record = await dnsProvider.createRecord({ fullRecord: '___certd___.__test__.certd.xyz', type: 'TXT', value: 'aaaa' })
|
||||
console.log('recordId', record.id)
|
||||
expect(record.id != null).ok
|
||||
|
||||
await dnsProvider.removeRecord({ fullRecord: '___certd___.__test__.certd.xyz', type: 'TXT', value: 'aaaa', record })
|
||||
})
|
||||
|
||||
it('#申请证书', async function () {
|
||||
this.timeout(300000)
|
||||
options.cert.domains = ['*.certd.xyz', 'certd.xyz']
|
||||
options.cert.dnsProvider = 'dnspod'
|
||||
options.args = { forceCert: true }
|
||||
const certd = new Certd()
|
||||
const cert = await certd.certApply(options)
|
||||
expect(cert).ok
|
||||
expect(cert.crt).ok
|
||||
expect(cert.key).ok
|
||||
expect(cert.detail).ok
|
||||
expect(cert.expires).ok
|
||||
})
|
||||
})
|
|
@ -14,20 +14,9 @@ describe('Certd', function () {
|
|||
const certd = new Certd()
|
||||
certd.writeCert('xiaojunnuo@qq.com', ['*.domain.cn'], { csr: 'csr', crt: 'aaa', key: 'bbb' })
|
||||
})
|
||||
it('#申请证书-aliyun', async function () {
|
||||
this.timeout(300000)
|
||||
options.args = { forceCert: true }
|
||||
const certd = new Certd()
|
||||
const cert = await certd.certApply(options)
|
||||
expect(cert).ok
|
||||
expect(cert.crt).ok
|
||||
expect(cert.key).ok
|
||||
expect(cert.detail).ok
|
||||
expect(cert.expires).ok
|
||||
})
|
||||
it('#readCurrentCert', async function () {
|
||||
const certd = new Certd()
|
||||
const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['*.docmirror.cn'])
|
||||
const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['*.domain.cn'])
|
||||
expect(cert).to.be.ok
|
||||
expect(cert.crt).ok
|
||||
expect(cert.key).to.be.ok
|
||||
|
|
|
@ -19,10 +19,7 @@ const defaultOptions = {
|
|||
cert: {
|
||||
domains: ['*.docmirror.club', 'docmirror.club'],
|
||||
email: 'xiaojunnuo@qq.com',
|
||||
challenge: {
|
||||
challengeType: 'dns',
|
||||
dnsProvider: 'aliyun'
|
||||
},
|
||||
dnsProvider: 'aliyun',
|
||||
csrInfo: {
|
||||
country: 'CN',
|
||||
state: 'GuangDong',
|
||||
|
|
|
@ -65,17 +65,6 @@
|
|||
resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
|
||||
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
|
||||
|
||||
acme-client@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/acme-client/-/acme-client-4.1.2.tgz#6072e98cc2e5aaf0a3f769a823b6bc68d034e8da"
|
||||
integrity sha512-3GlqDVWHgm0xpfnwOME/OpEBwEgO2vOplGEN8miWS7n7A28U9C7MtuTg6AuPYo8Lmqu4SADllnZrMLNasVNLEQ==
|
||||
dependencies:
|
||||
axios "0.21.0"
|
||||
backo2 "^1.0.0"
|
||||
bluebird "^3.5.0"
|
||||
debug "^4.1.1"
|
||||
node-forge "^0.10.0"
|
||||
|
||||
acorn-jsx@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
|
||||
|
@ -175,18 +164,13 @@ astral-regex@^1.0.0:
|
|||
resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
|
||||
integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
|
||||
|
||||
axios@0.21.0:
|
||||
version "0.21.0"
|
||||
resolved "https://registry.npmjs.org/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
|
||||
integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
resolved "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
|
||||
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
|
||||
dependencies:
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
backo2@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
|
||||
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
|
@ -202,11 +186,6 @@ binary-extensions@^2.0.0:
|
|||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
|
||||
integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
|
||||
|
||||
bluebird@^3.5.0:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
|
@ -750,9 +729,9 @@ flatted@^3.1.0:
|
|||
integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==
|
||||
|
||||
follow-redirects@^1.10.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
||||
version "1.13.1"
|
||||
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7"
|
||||
integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==
|
||||
|
||||
fs-extra@^8.1.0:
|
||||
version "8.1.0"
|
||||
|
@ -1404,6 +1383,11 @@ punycode@^2.1.0:
|
|||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qs@^6.9.4:
|
||||
version "6.9.4"
|
||||
resolved "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
|
||||
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
|
||||
|
||||
randombytes@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5a3f7446222fa123b645e51e954ccfd981f459bd
|
||||
Subproject commit 334a73743d03ca401258dce7ed479a969383689e
|
Loading…
Reference in New Issue