├── package.json
├── module_random.js
├── module_array.js
├── README_english.md
├── README.md
├── module_mail.js
├── index.js
├── module_pu_hackerone.js
└── yarn.lock
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vulspiderX",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "nodemailer": "^6.6.1",
8 | "puppeteer": "^1.14.0"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/module_random.js:
--------------------------------------------------------------------------------
1 | // 伪随机数范围 [low, high]
2 | // 中括号表示“包括” 即结果可能为最小和最大值
3 | function randomIntInc(low, high) {
4 | return Math.floor(Math.random() * (high - low + 1) + low)
5 | }
6 |
7 | //暴露函数 让index.js调用
8 | module.exports.randomIntInc = randomIntInc;
9 |
--------------------------------------------------------------------------------
/module_array.js:
--------------------------------------------------------------------------------
1 |
2 | function arraysEqual(a, b) {
3 | if (a === b) return true;
4 | if (a == null || b == null) return false;
5 | if (a.length != b.length) return false;
6 |
7 | for (var i = 0; i < a.length; ++i) {
8 | if (a[i] !== b[i]) return false;
9 | }
10 | return true;
11 | }
12 |
13 |
14 | //求两个数组的差集(特殊的是 这两个数组中的元素 也是数组)
15 | //res1 - res2
16 | function getdifference(res1, res2) {
17 | for (i = 0; i < res1.length; i++) {
18 | for (j = 0; j < res2.length; j++) {
19 | if (arraysEqual(res1[i], res2[j])) {
20 | res1.splice(i, 1);//删除1个 索引为i 的数组元素
21 | }
22 | }
23 | }
24 | return res1
25 | }
26 |
27 |
28 | //暴露函数 让index.js调用
29 | module.exports.getdifference = getdifference;
--------------------------------------------------------------------------------
/README_english.md:
--------------------------------------------------------------------------------
1 | # VulSpiderX
2 |
3 | [english](README_english.md) | [中文文档](README.md)
4 |
5 | It runs in the background and gets the latest information on Hackerone every 10 to 20 minutes (random). If there are the latest vulnerabilities, it sends emails (title + URL links) to security researchers actively.
6 |
7 | The crawl function uses Google puppeteer module to manipulate headless chromium to dynamically parse javascript bypass the anti-crawl mechanism.
8 |
9 | ### Screenshots
10 |
11 | 
12 | Recipient privacy security (any recipient cannot get the email addresses of other recipients)
13 |
14 | ### Configuration
15 |
16 | Edit `module_mail.js`
17 |
18 | * Configure the mail sender information
19 | * `host:` E-mail host address
20 | * `user =` E-mail account
21 | * `pass =` E-mail password
22 |
23 | * Configure recipient address
24 | * `recipients =` recipient address
25 |
26 | ### Usage
27 |
28 | >Please ensure that you have installed node.js and the package manager yarn(I use the environment Mac OS + node v10.15.3).
29 | >Other environments are not actually tested yet.
30 |
31 | ```
32 | # Install dependent libraries
33 | yarn install
34 |
35 | # Run (save the log)
36 | node index.js > VulSpiderX.log
37 | ```
38 |
39 | ### Related projects
40 |
41 | * [1135/VulSpider](https://github.com/1135/VulSpider)
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VulSpiderX
2 |
3 | [english](README_english.md) | [中文文档](README.md)
4 |
5 | 功能说明: 本程序在后台运行,每10到20分钟(随机)获取Hackerone的最新信息,如果有最新的漏洞,主动发送电子邮件(标题+链接)给若干个安全研究人员。
6 |
7 | 技术说明: 本程序使用node.js开发,爬取功能使用了Google puppeteer模块来模拟人工操作headless chromium,同时动态解析javascript,以绕过反爬机制。
8 |
9 |
10 | ### 实现效果
11 |
12 | 
13 |
14 | 收件人隐私安全(任一收件人无法得到其他收件人的邮箱地址)
15 |
16 | ### 配置参数
17 |
18 | 编辑`module_mail.js`进行配置
19 |
20 | * 配置发件人信息
21 | * `host: ` 邮箱服务地址
22 | * `port: ` 邮件服务端口 建议使用SMTP-over-SSL协议(通常为465端口) 不建议使用SMTP协议(通常为25端口)
23 | * `secureConnection: ` SMTP-over-SSL协议则设置为true 否则为false
24 | * `user =` 邮箱账号
25 | * `pass =` 邮箱密码
26 |
27 | * 配置收件人信息
28 | * `recipients =`收件人邮箱地址列表
29 |
30 | ### 使用方法
31 |
32 | 请确保您已经安装了 node.js 和 包管理器yarn
33 | ```shell
34 | # 自动安装本程序的依赖库
35 | yarn install
36 |
37 | # 运行 可选择保存程序日志
38 | node index.js > VulSpiderX.log
39 | ```
40 |
41 | * 运行环境
42 | * 环境1: macOS 10.14.4 + node v10.15.3 亲测通过 ✅
43 | * 环境2: CentOS 7 + node v11.0.0 亲测通过 ✅ 如果报错请安装你缺少的chromium的依赖库即可 如`yum install libXScrnSaver*` 更多参考[puppeteer/troubleshooting.md](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-on-google-cloud-functions)
44 | * 其他: 暂未测试
45 |
46 | ### 更新日志
47 |
48 | 2019.4 开发完成. 2019-2024.2持续可用.
49 |
50 | 2024.4 更新完成. Hackerone官网前端页面发生变更, 已修改相关提取数据的代码, 已更新到这个公开仓库.
51 |
52 |
53 | ### 相关项目
54 |
55 | * [1135/VulSpider: 本程序在后台持续运行,获取最新漏洞及每日简报,发送邮件给安全人员。](https://github.com/1135/VulSpider)
56 |
--------------------------------------------------------------------------------
/module_mail.js:
--------------------------------------------------------------------------------
1 | var nodemailer = require('nodemailer');
2 |
3 | var user = 'xxxx@aliyun.com';//发件 账号
4 | var pass = 'xxxx';//发件 密码
5 | var recipients = "1@sohu.com, 2@126.com";//收件地址 列表
6 |
7 |
8 | async function send_a_mail(title_of_mail, content_of_mail , one_pdf_file) {
9 |
10 | var transporter = nodemailer.createTransport({
11 | host: "smtp.aliyun.com",
12 | //port: 25, // SMTP
13 | port: 465, // SMTPS(SMTP-over-SSL)
14 | secureConnection: true, // SSL
15 | auth: {
16 | user: user,
17 | pass: pass,
18 | }
19 | });
20 |
21 | // 发送邮件的配置信息 - 不带附件
22 | var mailOptions = {
23 | from: "VulX <" + user + ">", // 发件人
24 | //to: recipients,
25 | bcc: recipients,//bcc是密送
26 | subject: title_of_mail, // 标题
27 | //text和html两者只支持一种
28 | text: content_of_mail, // 内容
29 | //html: 'Hello world ?' // html 内容
30 | };
31 |
32 |
33 | // 发送邮件的配置信息 - 带附件
34 | var mailOptions_with_attachment = {
35 | from: "VulX <" + user + ">", // 发件人
36 | //to: recipients,
37 | bcc: recipients,
38 | subject: title_of_mail, // 标题
39 | //text和html两者只支持一种
40 | text: content_of_mail, // 内容
41 | //html: 'Hello world ?' // html 内容
42 | attachments: [
43 | // { // utf-8 string as an attachment
44 | // filename: 'text1.txt',
45 | // content: 'hello world!'
46 | // },
47 |
48 | { // binary buffer as an attachment
49 | filename: title_of_mail + '.pdf',
50 | content: one_pdf_file
51 | }]
52 | };
53 |
54 |
55 |
56 | function callbackit(error, info) {
57 | if (error) {
58 | console.log(error)
59 | return console.log(error);
60 | // console.log(error)
61 | // transporter.sendMail(mailOptions,callbackit)//重新发送
62 | // return console.log("[mail]fail! retry..."+ mailOptions.subject + mailOptions.text)
63 | }
64 | console.log('Message sent: ' + info.response);
65 |
66 | }
67 |
68 | if(one_pdf_file == -1 ){
69 | //无需附件
70 | // send mail with defined transport object
71 | await transporter.sendMail(mailOptions, callbackit);
72 |
73 | }
74 | else
75 | { //需要附件
76 | // send mail with defined transport object
77 | await transporter.sendMail(mailOptions_with_attachment, callbackit);
78 | }
79 |
80 | }
81 |
82 |
83 | //暴露函数 让index.js调用
84 | module.exports.send_a_mail = send_a_mail;
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const module_array = require('./module_array');
2 | const module_mail = require('./module_mail');
3 | const module_pu_hackerone = require('./module_pu_hackerone');
4 | const moudule_random = require('./module_random')
5 |
6 | var oldarray = [];
7 | var result_array = [];
8 | var diffarray = [];
9 | var crawl_count = 0;
10 |
11 |
12 | //定义sleep函数
13 | function sleep(ms) {
14 | return new Promise(resolve => setTimeout(resolve, ms || 1000));
15 | }
16 |
17 | // 输出当前时间
18 | function print_current_time() {
19 | var date = new Date();
20 | var year = date.getFullYear();
21 | var month = date.getMonth() + 1;
22 | var day = date.getDate();
23 | var hour = date.getHours();
24 | var minute = date.getMinutes();
25 | var second = date.getSeconds();
26 | console.log(year + '.' + month + '.' + day + ' ' + hour + ':' + minute + ':' + second);
27 |
28 | }
29 |
30 |
31 |
32 | //发送邮件 逐条发送
33 | async function sendmail(arr) {
34 | console.log("-----[mail]sending")
35 |
36 | arr.reverse();//数组逆序 以便发送后邮件显示顺序为由新到旧 第一条最新
37 |
38 | for (var index = 0; index < arr.length; index++) {
39 |
40 | let one_title = arr[index][0];
41 | let one_content = arr[index][1];
42 | await module_mail.send_a_mail(one_title, one_content);// 漏洞标题 漏洞url
43 | await sleep(20 * 1000);//20秒后继续发送下一封邮件 避免ban
44 | }
45 |
46 | console.log("-----[mail]done")
47 | }
48 |
49 |
50 | async function mainlogic() {
51 |
52 | //爬取 计时开始
53 | const startDate = new Date().getTime();
54 |
55 | //爬取次数 第几次爬取
56 | crawl_count += 1;
57 |
58 | console.log('-----------------------------------');
59 |
60 |
61 | console.log(`[crawl]times: ${crawl_count}`);//爬取次数
62 |
63 | result_array = await module_pu_hackerone.crawl();
64 |
65 | //爬取 计时结束
66 | console.log(`[crawl] Time elapsed ${Math.round((new Date().getTime() - startDate) / 1000)} s`);
67 |
68 | //console.log(result_array)
69 | if (result_array != null) {//res不为空
70 | console.log('items count: ', result_array.length);
71 | //console.log(`\n[crawl]data: ${res}`);//本次爬取的数据
72 |
73 |
74 | if (crawl_count == 1) {//首次爬取
75 | // console.log("first")
76 | console.log(result_array)
77 |
78 | //逐条发送 可能因为一次性发送多封邮件被ban
79 | //sendmail(res);
80 |
81 | var result = "The program runs successfully.\nHere are the results of the first crawl.\nThe email address will receive the latest information in the future.\n\n-----\n\n";
82 |
83 | for (var index = 0; index < result_array.length; index++) {
84 | let one_title = result_array[index][0];
85 | let one_content = result_array[index][1];
86 | result += one_title + "\n" + one_content + "\n\n========\n\n" // 换行
87 | }
88 |
89 |
90 |
91 | sendmail([["Running...", result]]);
92 |
93 | oldarray = result_array.concat()//深拷贝 数组
94 |
95 | }
96 | else {
97 |
98 | //求差集
99 | //result_array - oldarray
100 | diffarray = module_array.getdifference(result_array.concat(), oldarray)
101 |
102 | if (diffarray.length > 0) {//如果有新增内容
103 | console.log('diff:', diffarray);//新增的数量
104 |
105 | console.log("\nall:")
106 | console.log(result_array)
107 | if (diffarray.length < 9){
108 | sendmail(diffarray);
109 | }
110 | else{
111 | console.log('skip')
112 | }
113 | oldarray = result_array.concat()//深拷贝 数组
114 |
115 | }
116 | else {//没有新增内容
117 | console.log("diff: 0")
118 | }
119 |
120 | }
121 |
122 | }
123 | else {
124 | console.log("it is null.")
125 | }
126 |
127 | console.log('-----------------------------------');
128 |
129 | }
130 |
131 |
132 | async function app() {
133 |
134 | while (1) {
135 | await mainlogic();
136 | print_current_time()
137 | let wait_time = moudule_random.randomIntInc(10, 20) * 60 * 1000;
138 | console.log("Wait " + wait_time / (60 * 1000) + " minutes for the next crawl.");
139 | await sleep(wait_time);//每两次爬取之间的时间间隔为10-20分钟
140 | }
141 |
142 | }
143 |
144 | app()
145 |
--------------------------------------------------------------------------------
/module_pu_hackerone.js:
--------------------------------------------------------------------------------
1 | const puppeteer = require('puppeteer');
2 |
3 |
4 | //模拟移动设备 默认支持列表 https://github.com/GoogleChrome/puppeteer/blob/master/DeviceDescriptors.js
5 | //const devices = require('puppeteer/DeviceDescriptors');
6 | //const iPhone = devices['iPhone X'];
7 |
8 |
9 | async function crawl() {
10 |
11 | //const puppeteer = require('puppeteer');
12 |
13 | //模拟移动设备 默认支持列表 https://github.com/GoogleChrome/puppeteer/blob/master/DeviceDescriptors.js
14 | //const devices = require('puppeteer/DeviceDescriptors');
15 | //const iPhone = devices['iPhone X'];
16 |
17 |
18 |
19 | //运行浏览器
20 | const browser = await
21 | puppeteer.launch({
22 | //headless: false,// false则显示浏览器窗口
23 | //devtools: true, //是否为每个选项卡自动打开DevTools面板 (该选项只有当 headless 选项为 false 的时候有效)
24 | slowMo: 250,//浏览器每个操作的间隔时间 慢下来以便观察 slow down by 250ms
25 | defaultViewport: { width: 1440, height: 821 },//修改viewport为mbp15下用chrome时的大小 //默认viewport为 800x600
26 | ignoreHTTPSErrors: true, //忽略https错误
27 | args: [
28 | // browser proxy
29 | //'--proxy-server=127.0.0.1:8080',
30 |
31 | //设置整个浏览器的user-agent为 Mac+chrome
32 | '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
33 |
34 | // 已知1: 如果在 mac系统下 开启chromium沙箱 正常运行.
35 | // 已知2: 如果在 linux和windows系统下 开启chromium沙箱 可能兼容性不佳 要么关闭沙箱 要么尝试使用参数 --enable-features=UseOzonePlatform
36 |
37 | //'--no-sandbox',
38 | //'--disable-setuid-sandbox',
39 | ],
40 | });
41 |
42 |
43 | let page1 = await browser.newPage();
44 | //await page.emulate(iPhone);
45 | let url1 = 'https://hackerone.com/hacktivity/overview?queryString=disclosed%3Atrue&sortField=latest_disclosable_activity_at&sortDirection=DESC&pageIndex=0';
46 |
47 |
48 |
49 | /*
50 | 删除部分代码:
51 | 由于新版本的hackerone网站(2024年) 已经不是懒加载了 所以不需要 滚动/向下翻页 了.
52 | */
53 |
54 |
55 |
56 |
57 | //---------------------
58 | try {
59 |
60 | // 启动浏览器
61 | await page1.evaluateOnNewDocument(() => {
62 | Object.defineProperty(navigator, 'webdriver', {
63 | get: () => undefined,
64 | });
65 | })
66 |
67 | // 跳转配置
68 | await
69 | page1.goto(
70 | url1,
71 | {
72 | waitUntil: 'networkidle2',//networkidle2 表示500毫秒内 没有 多于2个网络连接时 结束navigation导航 //networkidle0表示500毫秒内 没有任何网络连接时 结束navigation导航
73 | timeout: 400 * 1000,//最大导航时间(以毫秒为单位),默认为30秒,传递0表示禁用超时(disable timeout) 一直等待(好像是600秒)
74 | referer: 'https://www.hackerone.com/', //请求头中加入referer
75 | }
76 | );
77 |
78 |
79 |
80 | //等待页面内容的加载.
81 | await page1.waitForSelector('input[data-testid="hacktivity-search-input-input-input"]'); //等待具有 name="search" 属性的 元素加载到 DOM 中,并且该元素是可见的和可交互的。
82 |
83 |
84 |
85 |
86 |
87 |
88 | //-----提取内容
89 |
90 | //在浏览器console调试
91 | // 获取漏洞标题
92 | // 筛选1 document.querySelectorAll('div.spec-hacktivity-content>a')[0].innerText
93 | // 说明 因为未公开的漏洞标题 没有a标签 所以这个筛选只能找到不被隐藏的标题。 无法找到隐藏的标题
94 |
95 | // 筛选2 document.querySelectorAll('div.spec-hacktivity-content')[16].outerText
96 | // 如果 隐藏 不能被展示 爬到的内容为 "closed 2 hrs agoBy batee5a to InnoGames$300.00"
97 |
98 |
99 | // 获取漏洞链接
100 | // 筛选1 document.querySelectorAll('div.spec-hacktivity-content>a')[0].href
101 |
102 | let eleCount = await page1.evaluate((sel) => {
103 | // return document.querySelectorAll('div.spec-hacktivity-content>a').length;
104 | return document.querySelectorAll('div[data-testid="hacktivity-item"]').length;
105 | });
106 |
107 |
108 | //输出爬取的 元素条数 数据量
109 | console.log(eleCount);
110 |
111 | var result;//声明变量
112 | if (eleCount != 0) {
113 | result = await page1.evaluate((sel, eleCount) => {
114 | let element = document.querySelectorAll(sel);//获取文档中所有 'div.react-flex-view>a' 元素的NodeList
115 | console.log(element);
116 |
117 | let tempArray1 = [];//定义空数组
118 |
119 |
120 | for (let i = 0; i <= eleCount - 1; i++) {
121 | console.log(i);
122 | // console.log(element[i]?.innerText);
123 |
124 |
125 | const one_item = {
126 | title: element[i].querySelector('div[data-testid="report-title"]')?.innerText,
127 | severity: element[i].querySelector('span[data-testid="report-severity"]')?.innerText,
128 | reward奖金: element[i].querySelector('span[data-testid="report-reward"]')?.innerText,
129 | status: element[i].querySelector('div[data-testid="report-status"]')?.innerText,
130 | summary: element[i].querySelector('div[class="interactive-markdown text-sm w-full"]')?.innerText,
131 | link: element[i].querySelector('a[href^="/"]')?.href,
132 | };
133 |
134 |
135 |
136 | // let one_item_title = element[i].querySelector('div[data-testid="report-title"]')?.innerText;
137 | // let one_item_severity = element[i].querySelector('span[data-testid="report-severity"]')?.innerText;
138 |
139 | // let one_item_reward = element[i].querySelector('span[data-testid="report-reward"]')?.innerText;
140 |
141 | // let one_item_status = element[i].querySelector('div[data-testid="report-status"]')?.innerText;
142 | // let one_item_disclosedAt = element[i].querySelector('div[data-testid="report-disclosed-at"]')?.innerText;
143 | // let one_item_reporter = element[i].querySelector('a[href^="/"]')?.innerText;
144 | // let one_item_summary = element[i].querySelector('div[class="interactive-markdown text-sm w-full"]')?.innerText;
145 |
146 |
147 | // let one_item = [one_item_title, one_item_severity, one_item_reward, one_item_status, one_item_disclosedAt, one_item_reporter, one_item_summary];
148 | // const oneItemString = one_item.join('\n\n\n');
149 |
150 | const oneItemString = JSON.stringify(one_item, null, 2) + '\n\n\n🔗 ' + one_item.link;
151 |
152 | tempArray1[i] = [one_item.title, oneItemString]
153 | // element[i].innerText+'\n'+element[i].href;//取出某个元素 的innerText
154 |
155 | }
156 | return tempArray1
157 | }, 'div[data-testid="hacktivity-item"]', eleCount);
158 |
159 | //console.log(result)
160 |
161 | }
162 | }
163 | catch (err) {
164 | console.log(`An error occured.h1_[will_close_browser]`);
165 | await browser.close(); //已经出现异常 那就关闭浏览器 等待下次爬
166 | console.log(err);
167 |
168 | }
169 | finally {
170 | await browser.close();
171 | return result;
172 | }
173 |
174 |
175 | }
176 |
177 |
178 | //暴露函数 让index.js调用
179 | module.exports.crawl = crawl;
180 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | agent-base@^4.3.0:
6 | version "4.3.0"
7 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
8 | integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
9 | dependencies:
10 | es6-promisify "^5.0.0"
11 |
12 | async-limiter@~1.0.0:
13 | version "1.0.1"
14 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
15 | integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
16 |
17 | balanced-match@^1.0.0:
18 | version "1.0.2"
19 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
20 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
21 |
22 | brace-expansion@^1.1.7:
23 | version "1.1.11"
24 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
25 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
26 | dependencies:
27 | balanced-match "^1.0.0"
28 | concat-map "0.0.1"
29 |
30 | buffer-from@^1.0.0:
31 | version "1.1.1"
32 | resolved "http://registry.npm.taobao.org/buffer-from/download/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
33 | integrity sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=
34 |
35 | concat-map@0.0.1:
36 | version "0.0.1"
37 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
38 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
39 |
40 | concat-stream@1.6.2:
41 | version "1.6.2"
42 | resolved "http://registry.npm.taobao.org/concat-stream/download/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
43 | integrity sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=
44 | dependencies:
45 | buffer-from "^1.0.0"
46 | inherits "^2.0.3"
47 | readable-stream "^2.2.2"
48 | typedarray "^0.0.6"
49 |
50 | core-util-is@~1.0.0:
51 | version "1.0.2"
52 | resolved "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
53 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
54 |
55 | debug@2.6.9:
56 | version "2.6.9"
57 | resolved "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
58 | integrity sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=
59 | dependencies:
60 | ms "2.0.0"
61 |
62 | debug@^3.1.0:
63 | version "3.2.6"
64 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
65 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
66 | dependencies:
67 | ms "^2.1.1"
68 |
69 | debug@^4.1.0:
70 | version "4.1.1"
71 | resolved "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
72 | integrity sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=
73 | dependencies:
74 | ms "^2.1.1"
75 |
76 | es6-promise@^4.0.3:
77 | version "4.2.8"
78 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
79 | integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
80 |
81 | es6-promisify@^5.0.0:
82 | version "5.0.0"
83 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
84 | integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
85 | dependencies:
86 | es6-promise "^4.0.3"
87 |
88 | extract-zip@^1.6.6:
89 | version "1.6.7"
90 | resolved "http://registry.npm.taobao.org/extract-zip/download/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
91 | integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=
92 | dependencies:
93 | concat-stream "1.6.2"
94 | debug "2.6.9"
95 | mkdirp "0.5.1"
96 | yauzl "2.4.1"
97 |
98 | fd-slicer@~1.0.1:
99 | version "1.0.1"
100 | resolved "http://registry.npm.taobao.org/fd-slicer/download/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
101 | integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=
102 | dependencies:
103 | pend "~1.2.0"
104 |
105 | fs.realpath@^1.0.0:
106 | version "1.0.0"
107 | resolved "http://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
108 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
109 |
110 | glob@^7.1.3:
111 | version "7.1.3"
112 | resolved "http://registry.npm.taobao.org/glob/download/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
113 | integrity sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=
114 | dependencies:
115 | fs.realpath "^1.0.0"
116 | inflight "^1.0.4"
117 | inherits "2"
118 | minimatch "^3.0.4"
119 | once "^1.3.0"
120 | path-is-absolute "^1.0.0"
121 |
122 | https-proxy-agent@^2.2.1:
123 | version "2.2.4"
124 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
125 | integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
126 | dependencies:
127 | agent-base "^4.3.0"
128 | debug "^3.1.0"
129 |
130 | inflight@^1.0.4:
131 | version "1.0.6"
132 | resolved "http://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
133 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
134 | dependencies:
135 | once "^1.3.0"
136 | wrappy "1"
137 |
138 | inherits@2, inherits@^2.0.3, inherits@~2.0.3:
139 | version "2.0.3"
140 | resolved "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
141 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
142 |
143 | isarray@~1.0.0:
144 | version "1.0.0"
145 | resolved "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
146 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
147 |
148 | mime@^2.0.3:
149 | version "2.4.2"
150 | resolved "http://registry.npm.taobao.org/mime/download/mime-2.4.2.tgz#ce5229a5e99ffc313abac806b482c10e7ba6ac78"
151 | integrity sha1-zlIppemf/DE6usgGtILBDnumrHg=
152 |
153 | minimatch@^3.0.4:
154 | version "3.1.2"
155 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
156 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
157 | dependencies:
158 | brace-expansion "^1.1.7"
159 |
160 | minimist@0.0.8:
161 | version "0.0.8"
162 | resolved "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
163 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
164 |
165 | mkdirp@0.5.1:
166 | version "0.5.1"
167 | resolved "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
168 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
169 | dependencies:
170 | minimist "0.0.8"
171 |
172 | ms@2.0.0:
173 | version "2.0.0"
174 | resolved "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
175 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
176 |
177 | ms@^2.1.1:
178 | version "2.1.2"
179 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
180 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
181 |
182 | nodemailer@^6.6.1:
183 | version "6.6.1"
184 | resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.1.tgz#2a05fbf205b897d71bf43884167b5d4d3bd01b99"
185 | integrity sha512-1xzFN3gqv+/qJ6YRyxBxfTYstLNt0FCtZaFRvf4Sg9wxNGWbwFmGXVpfSi6ThGK6aRxAo+KjHtYSW8NvCsNSAg==
186 |
187 | once@^1.3.0:
188 | version "1.4.0"
189 | resolved "http://registry.npm.taobao.org/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
190 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
191 | dependencies:
192 | wrappy "1"
193 |
194 | path-is-absolute@^1.0.0:
195 | version "1.0.1"
196 | resolved "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
197 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
198 |
199 | pend@~1.2.0:
200 | version "1.2.0"
201 | resolved "http://registry.npm.taobao.org/pend/download/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
202 | integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
203 |
204 | process-nextick-args@~2.0.0:
205 | version "2.0.0"
206 | resolved "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
207 | integrity sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=
208 |
209 | progress@^2.0.1:
210 | version "2.0.3"
211 | resolved "http://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
212 | integrity sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=
213 |
214 | proxy-from-env@^1.0.0:
215 | version "1.0.0"
216 | resolved "http://registry.npm.taobao.org/proxy-from-env/download/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
217 | integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
218 |
219 | puppeteer@^1.14.0:
220 | version "1.14.0"
221 | resolved "http://registry.npm.taobao.org/puppeteer/download/puppeteer-1.14.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2Fpuppeteer%2Fdownload%2Fpuppeteer-1.14.0.tgz#828c1926b307200d5fc8289b99df4e13e962d339"
222 | integrity sha1-gowZJrMHIA1fyCibmd9OE+li0zk=
223 | dependencies:
224 | debug "^4.1.0"
225 | extract-zip "^1.6.6"
226 | https-proxy-agent "^2.2.1"
227 | mime "^2.0.3"
228 | progress "^2.0.1"
229 | proxy-from-env "^1.0.0"
230 | rimraf "^2.6.1"
231 | ws "^6.1.0"
232 |
233 | readable-stream@^2.2.2:
234 | version "2.3.6"
235 | resolved "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
236 | integrity sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=
237 | dependencies:
238 | core-util-is "~1.0.0"
239 | inherits "~2.0.3"
240 | isarray "~1.0.0"
241 | process-nextick-args "~2.0.0"
242 | safe-buffer "~5.1.1"
243 | string_decoder "~1.1.1"
244 | util-deprecate "~1.0.1"
245 |
246 | rimraf@^2.6.1:
247 | version "2.6.3"
248 | resolved "http://registry.npm.taobao.org/rimraf/download/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
249 | integrity sha1-stEE/g2Psnz54KHNqCYt04M8bKs=
250 | dependencies:
251 | glob "^7.1.3"
252 |
253 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
254 | version "5.1.2"
255 | resolved "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
256 | integrity sha1-mR7GnSluAxN0fVm9/St0XDX4go0=
257 |
258 | string_decoder@~1.1.1:
259 | version "1.1.1"
260 | resolved "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
261 | integrity sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=
262 | dependencies:
263 | safe-buffer "~5.1.0"
264 |
265 | typedarray@^0.0.6:
266 | version "0.0.6"
267 | resolved "http://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
268 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
269 |
270 | util-deprecate@~1.0.1:
271 | version "1.0.2"
272 | resolved "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
273 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
274 |
275 | wrappy@1:
276 | version "1.0.2"
277 | resolved "http://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
278 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
279 |
280 | ws@^6.1.0:
281 | version "6.2.2"
282 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
283 | integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==
284 | dependencies:
285 | async-limiter "~1.0.0"
286 |
287 | yauzl@2.4.1:
288 | version "2.4.1"
289 | resolved "http://registry.npm.taobao.org/yauzl/download/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
290 | integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=
291 | dependencies:
292 | fd-slicer "~1.0.1"
293 |
--------------------------------------------------------------------------------