├── _config.yml ├── .vscode └── settings.json ├── BurpSuite基本用例--BurpSuite手机中间人攻击.md ├── LICENSE ├── 未授权访问火眼红队工具.md ├── Bootstrap_considered_harmful.md ├── go-vuln-mangement.md ├── DNS缓存投毒.md ├── aardvark.md ├── Vue 2.5 发布了.md ├── Vue2.5中即将推出的TypeScript变化.md ├── 送给 ES6 开发者的7个hack .md ├── 🚀 宣布 Parcel:一个快速,零配置的 Web 应用打包工具 📦.md ├── 10个开发新手应该熟悉的github仓库.md ├── 2019年针对API安全的4点建议.md ├── Vue in 2016.md ├── 你可能不知道谷歌浏览器开发工具的其他用处.md ├── 3-parameters-to-measure-SAST-testing.md ├── 采用Flow以及TypeScript.md ├── 通过利用immutability的能力编写更安全和更整洁的代码.md ├── gitlab-bug-boungty-2022.md ├── 什么是服务端伪造(SSRF)?.md ├── 隐写术-深入研究PDF混淆漏洞.md ├── 对Pornhub的Web开发者的采访.md ├── 理解跨域资源共享.md ├── JavaScript是如何工作:系列一.md ├── mst-codeql.md ├── Chrome 0-day 漏洞.md ├── 你应该了解的5个 Logstash Filter 插件.md ├── 从仓库中移除敏感信息.md ├── 使用ELK Stack建设SIEM.md ├── 你并不知道Node.md ├── 出去就餐并且理解Express.js的基础知识.md ├── 正则表达式入门.md ├── circleci-incident.md ├── Javascript中Async-Await优于Promise的6个原因.md ├── Npm, yarn以及pnpm的不同之处.md ├── 如何写一个webpack插件.md ├── git-undo.md ├── README.md ├── Elasticsearch团队开发章程.md ├── 理解CSS Flexbox.md ├── Github Pages以及单页面应用.md ├── Service worker介绍.md └── 你真的理解grok吗?.md /_config.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | - jemoji 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "sarif-viewer.connectToGithubCodeScanning": "off" 3 | } -------------------------------------------------------------------------------- /BurpSuite基本用例--BurpSuite手机中间人攻击.md: -------------------------------------------------------------------------------- 1 | https://www.peerlyst.com/posts/burpsuite-basic-use-cases-burpsuite-mobile-mitm-attacks-ben-johnson-cissp-gmob-gwapt?utm_campaign=peerlyst_shared_post&utm_content=peerlyst_post&utm_medium=social&utm_source=twitter 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Neal Caffery 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /未授权访问火眼红队工具.md: -------------------------------------------------------------------------------- 1 | # 未授权访问火眼红队工具 2 | 3 | >原文:[Unauthorized Access of FireEye Red Team Tools](https://www.fireeye.com/blog/threat-research/2020/12/unauthorized-access-of-fireeye-red-team-tools.html) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ## 概述 12 | 13 | 一个由国家支撑的顶尖的竞争者窃取了火眼的红队工具。 因为我们认为竞争者已经拥有这些工具,并且我们不知道攻击者是否打算自己使用被盗的工具还是公开披露它们,所以火眼在此博客中发布了数百种对策,以使安全社区能够保护自己免受这些工具的攻击。我们已将防御策略整合到我们的火眼产品中,并与合作伙伴,政府机构共享了这些策略,以显着限制不良行为者利用红队工具的能力。 14 | 15 | 您可以在[这](https://github.com/fireeye/red_team_tool_countermeasures)火眼的 GitHub 仓库中找到策略列表。 16 | 17 | ## 红队工具和技术 18 | 19 | 红队是一组经过授权和组织的安全专家,模仿潜在的对手针对企业安全状况的攻击或利用能力。我们的红队的目的是通过演示成功攻击的影响并向防御者(即,蓝队)展示防御方法,以改善企业网络安全。过去15年来,我们一直在为全球客户进行红队评估。截至目前,我们已经建立了一套脚本,工具,扫描器和技术,以帮助改善客户的安全状况。不幸的是,这些工具被顶尖攻击者窃取。 20 | 21 | 被盗工具的范围从用于自动化侦察的简单脚本到类似于 CobaltStrike和 Metasploit 等公开可用技术的整个框架。许多红队工具已经发布给社区,并已分发到我们的开源虚拟机 CommandoVM 中。 22 | 23 | 其中一些工具是公开可用的工具,经过修改可以逃避基本的安全检测机制。其它的工具和框架是我们红队内部定制开发。 24 | 25 | ## 没有零日漏洞或者未知技术 26 | 27 | 攻击者窃取的红队工具不包含零日漏洞。这些工具采用了世界各地其他红队所使用的众所周知且有据可查的方法。尽管我们认为这种盗窃不会大大提高攻击者的整体能力,但火眼会尽一切努力防止这种情况的发生。 28 | 29 | 请务必注意,火眼尚未看到任何对手散布或使用这些工具,我们将继续与安全合作伙伴一起监视任何此类活动。 30 | 31 | ## 有益于社区的检测 32 | 33 | 为了使社区能够检测到这些工具,我们正在发布防御策略,以帮助组织识别这些工具(如果它们在野出现)。为了应对我们的红队工具的盗窃,我们针对 OpenIOC,Yara,Snort 和 ClamAV 等公开可用技术发布了数百种对策。 34 | 35 | 可在[此处](https://github.com/fireeye/red_team_tool_countermeasures)找到火眼 GitHub 仓库上的对策列表。我们将发布检测,并将随着我们开发新的或改进现有检测的主机,网络和基于文件的指标的重叠对策而继续更新公共存储库。 此外,我们在 GitHub 页面上发布了需要解决的 CVE 列表,以限制红队工具的有效性。 36 | 37 | ## 火眼产品能够帮助客户免于这些工具攻击 38 | 39 | 40 | 火眼的各个团队都在努力制定对策,以保护我们的客户和广大社区。 我们已将这些对策整合到我们的产品中,并与我们的合作伙伴(包括国土安全部)共享了这些对策,这些合作伙伴已将这些对策纳入其产品中,从而为社区提供了广泛的覆盖范围。 41 | 42 | 有关可用的检测签名的更多信息,可以在[GitHub仓库](https://github.com/fireeye/red_team_tool_countermeasures)中找到。 43 | -------------------------------------------------------------------------------- /Bootstrap_considered_harmful.md: -------------------------------------------------------------------------------- 1 | ## Bootstrap 被认为是有害的 2 | 3 | > 原文:[Bootstrap considered harmful](https://blog.sicara.com/a-progressive-web-application-with-vue-js-webpack-material-design-part-1-c243e2e6e402) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 这些年Bootstrap已经在前端项目中流行起来,它能够带来很多好处。然而,但是如果以你们的团队已经有了在职的前端开发人员,我觉得最好还是不要用Bootstrap,在某些地方,弊大于利。 12 | 13 | ### Bootstrap的好处是什么 14 | Bootstrap主要是栅格系统,但同时也带来了很多组件的样式表和脚本,包括表格,导航栏,进度条,页码,表单样式,模式和提示文本。在这篇文章,我所说的Bootstrap是包含它的所有功能的。 15 | Bootstrap是一个很好的工具对于一个纸箱装饰他们的程序但是无须担心结果的样式问题的后端开发人员。如果因为某些原因,预算或者什么的,你的团队没有前端开发人员或者设计人员,Bootstrap是一个绝佳的弥补方法。 16 | 对于设计人员来说,Bootstrap也是有用处的:它可以快速地从设计软件切换到浏览器中,不需要过多担心前端的代码设计。 17 | 即使是对于那些基本只专注于数据但是很少关注UI和布局的前端开发人员来说,Bootstrap也是一个绝佳的工具。 18 | 19 | ### 什么时候你最好别用它 20 | 21 | 然而,如果你的团队已经拥有了前端开发人员,使用Bootstrap可能会潜在的浪费他们宝贵的时间,并让他们可能从解决实际问题上转移注意力。Bootstrap做的正是前端开发人员所擅长的事情,但是用的是一种很通用的方式。你的网站或者网络app是非常特别的,因此如果你使用一个通用的系统可能会不太合适。这意味着为了实现这种特殊性将会包含很多的异常发生。 22 | 23 | ### 当需要很多异常来复位Bootstrap 24 | 25 | Bootstrap曾经是被Twitter 的开发人员用于系统化他们网络app的样式。如果你的网站app和他们的样式不一样,这意味着你需要解除他们中的某些样式。 26 | 27 | 很多网站和Twitter的样式并不相同。因此,如果他们装载了Bootstrap的时候,他们可能需要卸载很多地方。 28 | 29 | 在某些网站上,我看到有9/10的Bootstrap样式已经被网站自己的样式所替代。坦白说,这很荒谬。 30 | 31 | 32 | 33 | ### 当它让简单的事情变得复杂 34 | 35 | CSS是给网站添加一套简单的样式规则,这有时候可能会被重写。当你在你的网站使用Bootstrap的样式的时候,几乎所有的元素都是用一个复杂的样式规则。任何异常都会在它之上表现。问题是大多数网站他们的样式异常都被表现在Bootstrap之上。 36 | 37 | Bootstrap的样式是非常复杂的:你可以利用12列的栅格系统和任何元素相结合起来,对于需要特别处理的列则要区别对待。很多网站十分简单:它们在小屏幕设备上没有列或者只有一到两列在大一点的屏幕上。 38 | 39 | ### 当它产生技术债务的时候 40 | 41 | 前端依赖Bootstrap的时间越长,就会牵扯到更多的东西,更多的规则需要设置来覆盖Bootstrap的某些规则。这或多或少地让技术代码背负技术债务,尤其前端代码的部署需要手动的更新。随着依赖的增多,Bootstrap将变得更加难以移除。 42 | 43 | ### 当它命名一些不是你app的规定 44 | 45 | 命名是一件很困难的事情,为团队的应用中的规定命名需要花费相当多的时间。使用'btn'之类的缩写并不能很好的给组件命名。 46 | 47 | ### 结论 48 | 49 | Bootstrap可能对于产生网站的多个流程都起到了很大的帮助。但是它并不能让所有的事情都变得简单:相反,很多问题可以由前端开发人员专注于UI就能够更好地解决。 50 | -------------------------------------------------------------------------------- /go-vuln-mangement.md: -------------------------------------------------------------------------------- 1 | # Go 的漏洞管理 2 | 3 | >原文:[Vulnerability Management for Go](https://go.dev/blog/vuln) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 我们很高兴地宣布 Go 对漏洞管理的新支持,这是我们帮助 Go 开发人员了解可能影响他们的已知漏洞的第一步。 12 | 13 | 这篇文章概述了当前可用的内容以及该项目的后续计划。 14 | 15 | # 概述 16 | 17 | Go 提供工具来分析你的代码库来发现已知漏洞。该工具由 Go 漏洞数据库提供支持,该数据库由 Go 安全团队规划。Go 的工具通过仅显示代码实际调用的函数中的漏洞来减少结果中的噪音。 18 | 19 | ![Architecture diagram of Go's vulnerability management system](https://go.dev/blog/vuln/architecture.png) 20 | 21 | # Go 漏洞数据库 22 | 23 | Go 漏洞数据库 (https://vuln.go.dev) 是有关公共 Go 模块中可导入包中已知漏洞的综合信息源。 24 | 25 | 漏洞数据来自现有来源(例如 CVE 和 GHSA)以及来自 Go 包维护者的直接报告。Go 安全团队会审查这些信息并将其添加到数据库中。 26 | 27 | 我们鼓励包维护者在他们自己的项目中[提供](https://go.dev/s/vulndb-report-new)有关公共漏洞的信息,并[更新](https://go.dev/s/vulndb-report-feedback)其 Go 包中漏洞的现有信息。我们的目标是使报告过程成为一个非常容易的过程,因此请向我们反馈任何改进的[建议](https://golang.org/s/vuln-feedback)。 28 | 29 | Go 漏洞数据库可以在浏览器中的 pkg.go.dev/vuln 中查看。 有关数据库的更多信息,请参阅 go.dev/security/vuln/database。 30 | 31 | # 使用 govulcheck 检测漏洞 32 | 33 | 新的 [govulncheck 命令](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck)是一种低噪音、可靠的方式,让 Go 用户了解可能影响他们项目的已知漏洞。 Govulncheck 分析你的代码库并仅根据代码中的哪些函数传递调用易受攻击的函数来发现实际影响你的漏洞。 要开始使用 govulncheck,你可以从项目中运行以下命令: 34 | 35 | ``` 36 | $ go install golang.org/x/vuln/cmd/govulncheck@latest 37 | $ govulncheck ./... 38 | ``` 39 | 40 | Govulncheck 是一个独立的工具,允许在我们收集用户反馈的同时进行频繁更新和快速迭代。从长远来看,我们计划将 govulncheck 工具集成到主要的 Go 发行版中。 41 | 42 | 为了将漏洞检查直接集成到其他工具和流程中,[vulncheck](https://pkg.go.dev/golang.org/x/vuln/vulncheck) 包将 govulncheck 的功能导出为 Go API。 43 | 44 | # 集成 45 | 46 | 在开发和部署过程中尽早了解漏洞总是更好的。 为此,我们将漏洞检测集成到现有的 Go 工具和服务中,例如 [Go 包发现站点](https://pkg.go.dev/)。例如,[此页面](https://pkg.go.dev/golang.org/x/text?tab=versions)显示了 `golang.org/x/text` 的每个版本中的已知漏洞。 通过 VS Code Go 扩展的漏洞检查功能也即将推出。 47 | 48 | # 下一步 49 | 50 | 我们希望你会发现 Go 对漏洞管理的支持很有用,并帮助我们改进它! 51 | 52 | Go 对漏洞管理的支持是一项正在积极开发的新功能。你应该预料到一些错误和[限制](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Limitations)。 53 | 54 | 我们希望你通过以下方式做出贡献并帮助我们进行改进: 55 | 56 | * 为你维护的 Go 软件包[提供新的](https://golang.org/s/vulndb-report-new)和[更新](https://go.dev/s/vulndb-report-feedback)有关公共漏洞的现有信息 57 | * [参加此问卷调查](https://golang.org/s/govulncheck-feedback)以分享你使用 govulncheck 的经验 58 | * 向我们发送有关问题和功能请求的[反馈](https://golang.org/s/vuln-feedback) 59 | 60 | 我们很高兴与你合作,建立一个更好、更安全的 Go 生态系统。 61 | 62 | -------------------------------------------------------------------------------- /DNS缓存投毒.md: -------------------------------------------------------------------------------- 1 | ## DNS 缓存投毒 2 | 3 | > 原文:[DNS Cache Poisoning]( 4 | https://medium.com/iocscan/dns-cache-poisoning-bea939b5afaf) 5 | > 6 | > 译者:[madneal](https://github.com/madneal) 7 | > 8 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 9 | > 10 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 11 | 12 | ![](https://cdn-images-1.medium.com/max/2000/1*3kt_t9wSc7MP4Gu2rD7_gw.png) 13 | 14 | DNS 欺骗是 DNS 服务器记录更改导致恶意重定向流量的结果。DNS 欺骗可以通过直接攻击 DNS 服务器(我们将在这里讨论)或通过任何形式的专门针对 DNS 流量的中间人攻击来执行。 15 | 16 | DNS 缓存欺骗以一种利用 DNS 通信结构的方式明确地工作。当 DNS 服务器尝试在域上执行查找时,它会将请求转发到根权威 DNS,并迭代地沿着 DNS 服务器链向下查询,直到它到达域上的权威 DNS 服务器。由于本地 DNS 服务器不知道哪个服务器负责哪个域,并且不知道到每个权威服务器的完整路由,因此只要回复与查询匹配并且格式正确,它就会从任何地方接受对其查询的回复。攻击者可以通过在回复本地 DNS 服务器时击败实际的权威 DNS 服务器来利用此设计,如果这样做,本地 DNS 服务器将使用攻击者的 DNS 记录而不是实际的权威答案。由于 DNS 的性质,本地 DNS 服务器无法确定哪个回复是真实的,哪个是假的。 17 | 18 | 由于 DNS 服务器将在内部缓存查询,因此每次请求域时,他们不必浪费时间查询权威服务器,从而加剧了这种攻击。这带来了另一个问题,因为如果攻击者可以击败权威DNS 服务器进行回复,那么攻击者记录将被本地 DNS 服务器缓存,这意味着任何使用本地DNS服务器的用户都将获得攻击者记录,可能会重定向所有使用该本地 DNS 服务器的用户都可以访问攻击者的网站。 19 | 20 | ![DNS Cache Poisoning Workflow](https://cdn-images-1.medium.com/max/2000/1*iBZM5hvnXRvelyJ0E1KRig.png) 21 | 22 | ## DNS 缓存投毒的例子 23 | 24 | **生日攻击的盲目响应伪造** 25 | 26 | DNS 协议交换不验证对递归迭代查询的响应。验证查询只会检查 16 位事务 ID 以及响应数据包的源 IP 地址和目标端口。在 2008 年之前,所有 DNS 使用固定端口53 解析.因此,除了事务 ID 之外,欺骗 DNS 回复所需的所有信息都是可预测的。用这种弱点攻击 DNS 被称为“生日悖论”,平均需要 256 次来猜测事务 ID。为了使攻击成功,伪造的 DNS 回复必须在合法权威响应之前到达目标解析器。如果合法响应首先到达,它将由解析器缓存,并且直到其生存时间(TTL)到期,解析器将不会要求权威服务器解析相同的域名,从而防止攻击者中毒映射该域,直到 TTL 到期。 27 | 28 | **Kaminsky 漏洞** 29 | 30 | 在 2008 年 在 Black Hat 上有人揭示了生日攻击的拓展,其中基本的盲猜技术保持不变。该攻击利用了 DNS 响应的基本特性,因为 DNS 响应可以是直接应答(请求的直接 IP 地址)或引用(对给定区域具有权威性的服务器)。生日攻击伪造了一个为给定域记录注入错误条目的答案。 Kaminsky 漏洞使用引用来绕过先前条目上的 TTL 对整个域进行错误输入。基本思想是攻击者选择他们希望攻击的域,然后向目标解析器查询尚未被解析器缓存的子域(定位不存在的子域是一个很好的选择,记录是没有被 DNS 解析器缓存)。由于子域不在缓存中,因此目标解析器向该域的权威服务器发送查询。正是在这一点上,攻击者用大量伪造的响应来淹没解析器,每个伪造的响应都有不同的伪造事务 ID 号。如果攻击者成功注入伪造响应,则解析器将为权威服务器缓存错误映射。对受感染域的目标解析器的未来 DNS 查询将导致所有请求被转发到攻击者控制器权威解析器,使攻击者能够提供恶意响应,而无需为每个新 DNS 记录注入假条目。 31 | 32 | **窃听** 33 | 34 | 许多增强 DNS 安全性的新提议包括源端口随机化,0x20 XOR 编码,WSEC-DNS,这些都取决于用于身份验证的组件的不对称可访问性。 换句话说,它们通过隐匿而不是通过身份验证和加密的机密性来提供安全性。他们的唯一目标是如上所述防止盲目攻击 使用这些安全方法仍然使 DNS 容易遭受受损服务器和网络窃听者的轻微攻击,以打破默默无闻并执行如上所述的相同攻击,这次没有盲目猜测。 即使在交换环境中,也可以使用 ARP 中毒和类似技术强制所有数据包进入恶意计算机,并且可以击破这种混淆技术。 35 | 36 | ## DNS 缓存投毒缓解 37 | 38 | **DNSSEC** 39 | 40 | 防止 DNS 缓存被投毒的最佳方法是实现加密和身份验证的安全方法。DNS 作为一种过时的协议以及整个互联网的支柱,令人惊讶的是仍然是一种未加密的协议,没有对它收到的条目和响应进行任何形式的验证。 41 | 42 | 当然,解决方案是提供一种称为 DNS Secure 或 [DNSSEC](https://medium.com/iocscan/how-dnssec-works-9c652257be0)的验证和身份验证方法。该协议创建了与 DNS 记录一起存储的唯一加密签名。然后 DNS 解析器使用签名来验证 DNS 响应,确保记录未被篡改。此外,它还提供了从 TLD 到域权威区域的信任链,确保了 DNS 解析的整个过程是安全的。 43 | 44 | 尽管有这些明显的好处,但 DNSSEC 的采用速度很慢,许多不那么受欢迎的 TLD 仍然没有利用 DNSSEC 来保证安全。主要问题是 DNSSEC 设置复杂,需要升级设备来处理新协议,另外由于历史上大多数 DNS 欺骗攻击的罕见和不可知性,DNSSEC 的实现不被视为优先级,通常只执行一次应用就达到其生命周期的终点。 45 | -------------------------------------------------------------------------------- /aardvark.md: -------------------------------------------------------------------------------- 1 | # 介绍 Aardvark:OpenAI 智能体安全研究员 2 | 3 | >原文:[3 parameters to measure SAST testing](https://openai.com/index/introducing-aardvark/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 今天,我们宣布推出 Aardvark,这是一家由 GPT-5 提供支持的智能体安全研究员。 12 | 13 | 软件安全是技术领域最关键、最具挑战性的前沿领域之一。每年,在企业和开源代码库中都会发现数以万计的新漏洞。防御者面临着在对手之前发现和修补漏洞的艰巨任务。在 OpenAI,我们正在努力使这种平衡向有利于防御者的方向倾斜。 14 | 15 | Aardvark 代表了人工智能和安全研究的突破:一种自主代理,可以帮助开发人员和安全团队大规模发现和修复安全漏洞。Aardvark 现已推出私人测试版,以验证和完善其在该领域的能力。 16 | 17 | ## Aardvark 的工作原理 18 | 19 | Aardvark 不断分析源代码仓库,以识别漏洞、评估可利用性、确定严重性优先级并提出有针对性的补丁。 20 | 21 | Aardvark 的工作原理是监控代码库的提交和更改、识别漏洞、如何利用它们并提出修复建议。Aardvark 不依赖传统的程序分析技术,如模糊测试或软件组合分析。相反,它使用大模型驱动的推理和工具使用来理解代码行为并识别漏洞。Aardvark 像人类安全研究人员一样寻找错误:通过阅读代码、分析代码、编写和运行测试、使用工具等等。 22 | 23 | ![](https://images.ctfassets.net/kftzwdyauwt9/4VNAPycxZna8DOgUmlDFuL/e5f0c2773a181f456f186ead677a9e02/Aardvark_Overview_Diagram_Desktop_Light__1_.svg?w=3840&q=80) 24 | 25 | Aardvark 依靠多阶段流水线来识别、解释和修复漏洞: 26 | 27 | * 分析:它首先分析完整的仓库,以生成反映其对项目安全目标和设计的理解的威胁模型。 28 | * 提交扫描:在提交新代码时,它通过针对整个仓库和威胁模型检查提交级别更改来扫描漏洞。首次连接仓库时,Aardvark 将扫描其历史记录以识别现有问题。Aardvark 逐步解释了它发现的漏洞,并注释代码以供人工审查。 29 | * 验证:一旦 Aardvark 发现潜在漏洞,它将尝试在隔离的沙盒环境中触发它以确认其可利用性。Aardvark 描述了为帮助确保向用户返回准确、高质量和低误报见解而采取的步骤。 30 | * 修复:Aardvark 与 OpenAI Codex 集成,帮助修复发现的漏洞。它将 Codex 生成和 Aardvark 扫描的补丁附加到每个发现中,以便人工审查和高效的一键式补丁。 31 | 32 | Aardvark 与工程师一起工作,与 GitHub、Codex 和现有工作流程集成,在不减慢开发速度的情况下提供清晰、可作的见解。虽然 Aardvark 是为安全而构建的,但在我们的测试中,我们发现它还可以发现逻辑缺陷、不完整的修复和隐私问题等错误。 33 | 34 | 35 | ## 当下的真正影响 36 | 37 | Aardvark 已经服务了几个月,在 OpenAI 的内部代码库和外部 alpha 合作伙伴的代码库中持续运行。在 OpenAI 内部,它暴露了有意义的漏洞,并助长了 OpenAI 的防御态势。合作伙伴强调了其分析的深度,Aardvark 发现了仅在复杂条件下才会出现的问题。 38 | 39 | 在对“黄金”存储库的基准测试中,Aardvark 识别了 92% 的已知和合成引入的漏洞,证明了高召回率和现实世界的有效性。 40 | 41 | 42 | ## Aardvark 开源 43 | 44 | Aardvark 还应用于开源项目,它已经发现了许多漏洞,我们负责任地披露了许多漏洞,其中 10 个漏洞已获得公共漏洞和暴露 (CVE) 标识符。 45 | 46 | 作为数十年来开放研究和负责任披露的受益者,我们致力于回馈社会,贡献工具和发现,使数字生态系统对每个人来说都更安全。我们计划为选择非商业性开源存储库提供无偿扫描,为开源软件生态系统和供应链的安全做出贡献。 47 | 48 | 我们最近[更新](https://openai.com/index/scaling-coordinated-vulnerability-disclosure/)了[外部协同披露政策](https://openai.com/policies/outbound-coordinated-disclosure-policy/),该政策采取了对开发人员友好的立场,专注于协作和可扩展的影响,而不是可能给开发人员带来压力的严格披露时间表。我们预计像 Aardvark 这样的工具将导致越来越多的问题被发现,并希望以可持续的方式合作以实现长期弹性。 49 | 50 | 51 | ## 为什么重要 52 | 53 | 软件现在是每个行业的支柱,这意味着软件漏洞对企业、基础设施和社会来说是一种系统性风险。仅在 2024 年,就报告了超过 40,000 个 CVE。我们的测试表明,大约 1.2% 的提交引入了错误——微小的更改可能会产生巨大的后果。 54 | 55 | Aardvark 代表了一种新的防御者优先模式:代理安全研究人员通过随着代码的发展提供持续保护来与团队合作。通过及早发现漏洞、验证现实世界的可利用性并提供明确的修复程序,Aardvark 可以在不减缓创新的情况下增强安全性。我们相信扩大安全专业知识的获取范围。我们从私人测试版开始,并将随着我们的学习扩大可用性。 56 | 57 | ## 私人测试版现已开放 58 | 59 | 我们邀请精选合作伙伴加入 Aardvark 私人测试版。参与者将获得早期访问权,并直接与我们的团队合作,以完善检测准确性、验证工作流程和报告经验。 60 | 61 | 我们希望验证各种环境中的性能。如果您的组织或开源项目有兴趣加入,您可以在[这里](https://www.openai.com/form/aardvark-beta-signup)申请。 -------------------------------------------------------------------------------- /Vue 2.5 发布了.md: -------------------------------------------------------------------------------- 1 | ## Vue 2.5 发布了 2 | 3 | > 原文:[Vue 2.5 released](https://medium.com/the-vue-point/vue-2-5-released-14bd65bf030b) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 我们很高兴宣布 Vue 2.5 Level E 的发布!本次发布包括多个功能提升并且我们推荐你查看[发布说明](https://github.com/vuejs/vue/releases/tag/v2.5.0)来获取完整详细信息。 在这篇文章中,我们将重点介绍一些更重要的的变化:更好的 TypeScript 集成,更好的错误处理,更好地支持单文件组件中的函数式组件以及与环境无关的服务端渲染。 12 | 13 | ## 更好的 TypeScript 集成 14 | 15 | ![](https://cdn-images-1.medium.com/max/3200/1*vB-z-t961mJnd4a6re02Iw.png) 16 | 17 | 得益于 TypeScript 团队的帮助,2.5 提供了大大改进的类型声明,可以与 Vue 的开箱即用的 API 一起使用,而不需要组件类装饰器。 新的类型声明还可以让 [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur) 等编辑器扩展功能更强大,为纯 JavaScript 用户提供更好的Intellisense 支持。 更多详细信息,请查看[我们之前关于更改的信息](https://medium.com/the-vue-point/upcoming-typescript-changes-in-vue-2-5-e9bd7e2ecf08)。 18 | 19 | *感谢来自 TypeScript 团队的 Daniel Rosenwasser 发起的 PR,以及核心团队成员 Herrington Darkholme和 Katashin 的改进和审查。* 20 | 21 | > 注意:TypeScript 用户还应将以下包更新为最新版本从而兼容类型声明:`vue-router`,`vuex`,`vuex-router-sync` 和`vue-class-component`。 22 | 23 | ## 更好地错误处理 24 | 25 | ![](https://cdn-images-1.medium.com/max/2000/1*ZHamhzmnoQcQTxCJE3cmvA.jpeg) 26 | 27 | 在2.4及更早版本中,我们通常使用全局 `config.errorHandleroption` 来处理应用程序中的意外错误。 我们还有`renderError` 组件选项来处理渲染函数中的错误。 但是,我们缺少处理应用程序特定部分内的泛型错误的机制。 28 | 29 | 在2.5中,我们引入了新的 `errorCaptured` 钩子。 具有此钩子的组件捕获其子组件树(不包括其自身)中的所有错误(不包括在异步回调中调用的那些)。 如果你熟悉React,这与 React 16 中引入的[错误边界](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html#introducing-error-boundaries)的概念相似。钩子接收与全局 `errorHandler` 相同的参数,你可以利用这个钩子来[优雅地处理和显示错误](https://gist.github.com/yyx990803/9bdff05e5468a60ced06c29c39114c6b#error-handling-with-errorcaptured-hook)。 30 | 31 | ## 更好地支持 `SFC` 中的函数式组件 32 | 33 | ![](https://cdn-images-1.medium.com/max/2828/1*jg9qGPkPadGBEa-KUPrMpA.png) 34 | 35 | 使用 `vue-loader> = 13.3.0` 和 `Vue 2.5`,在 `* .vue` 文件中定义为单个文件组件的函数式组件现在可以得到[正确的模板编译,Scoped CSS和热重新加载支持](https://vue-loader.vuejs.org/en/features/functional.html)。 这使得将叶子组件转换为函数式的更为容易,从而进行性能优化。 36 | 37 | *感谢核心团队成员[Blake Newman](https://github.com/blake-newman) 对于这些功能做出的贡献。 38 | 39 | ## 与环境无关的服务端渲染 40 | 41 | `vue-server-renderer` 的默认构建假定一个 Node.js 环境,这使得它在有的 JavaScript 运行时(如 [php-v8js](https://github.com/phpv8/v8js) 或Nashorn)中不可用。 在 2.5 中,我们已经发布了[一个与环境无关的 `vue-server-renderer` 版本](https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/basic.j),可以在浏览器或纯 JavaScript 引擎中使用。 这可以打开有趣的策略,例如[直接在 PHP 进程中使用 Vue 服务端渲染](https://gist.github.com/yyx990803/9bdff05e5468a60ced06c29c39114c6b#environment-agnostic-ssr)。 42 | 43 | 同样,我们建议你查看完整的[发布说明](https://github.com/vuejs/vue/releases/tag/v2.5.0)从而了解其他 API 的改进,包括 `v-on`,`v-model`,`scoped slot`,`provide/inject` 等。 你可能也对我们的[公共蓝图](https://github.com/vuejs/roadmap)感兴趣,详细说明了团队的工作。 干杯! 44 | -------------------------------------------------------------------------------- /Vue2.5中即将推出的TypeScript变化.md: -------------------------------------------------------------------------------- 1 | ## Vue 2.5中即将推出的TypeScript变化 2 | 3 | ## 输入提升 4 | 5 | 自Vue 2.0发布以来,我们一直在收到更好的 TypeScript 集成请求。 自从发布以来,我们已经为大多数核心库(`vue`, `vue-router`, `vuex`)包含了官方的 TypeScript 类型声明。 然而,当使用开箱即用的 Vue API 时,目前的集成有些缺乏。 例如,TypeScript 不能轻易地推断 Vue 使用的基于对象的默认 API 中 `this` 的类型。 为了使我们的 Vue 代码可以很好地使用 TypeScript,我们必须使用 `vue-class-component` 装饰器,这样我们可以使用基于类的语法来创建 Vue 组件。 6 | 7 | 对于喜欢基于类的API的用户来说,这可能已经足够好了,但对于仅仅为了类型推断的用户不得不使用不同的API是不幸的。 这也使得将现有 Vue 代码库迁移到 TypeScript 更具挑战性。 8 | 9 | 今年早些时候,TypeScript 引入了许多[新功能](https://github.com/Microsoft/TypeScript/pull/14141),这样就可以改进Vue的类型声明从而使得 TypeScript 可以更好地理解基于对象字面量的 API。 来自 TypeScript 团队的 Daniel Rosenwasser 开始了一个雄心勃勃的PR(现在由核心团队成员 HerringtonDarkholme 在[这](https://github.com/vuejs/vue/pull/6391)维护),一旦合并,将提供: 10 | 11 | * 使用默认的 Vue API 时,对于 `this` 可以使用适当的类型推断。 它也可以在单文件组件中工作! 12 | * 基于组件的 `props` 选项,对于 `this` 中的 props 输入推断。 13 | * 最重要的是,**这些改进也使得纯 JavaScript 用户受益匪浅!** 如果你使用 VSCode 与超级棒的的 [Vetur](https://github.com/vuejs/vetur) 扩展,你将获得大大改进的自动完成建议,甚至在Vue组件中使用纯 JavaScript 时也能获得输入提示! 这是因为[vue-language-server](https://www.npmjs.com/package/vue-language-server)是负责分析 Vue 组件的内部包,可以利用 TypeScript 编译器来提取有关你的代码的更多信息。 此外,任何支持语言服务器协议的编辑器都可以利用 [`vue-language-server`](https://github.com/vuejs/vetur/tree/master/server)来提供类似的功能。 14 | 15 | ![1-ftkupzygizn1es87jcbs8q](https://user-images.githubusercontent.com/12164075/31341266-932f5cc8-ad3b-11e7-8677-addf8d3ad5d4.gif) 16 | 17 | 对于那些好奇的人,你可以通过克隆这个 [playground 项目](https://github.com/octref/veturpack/tree/new-types)(确保获取 `new-types` 的分支)并使用 VSCode + Vetur 打开它来尝试一下! 18 | 19 | ## TypeScript用户可能需要的操作 20 | 21 | 输入升级将在 Vue 2.5 中发布,目前计划在10月初发布。 我们正在发布一个小版本,因为 JavaScript 公共 API 没有任何突破性的变化,但是升级可能需要现有的 TypeScript + Vue 用户采取一些操作。 这就是为什么我们现在宣布改变,以便你有足够的时间来计划升级。 22 | 23 | * 新的输入至少需要 TypeScript 2.4 版本,建议升级到最新版本的 TypeScript 以及 Vue 2.5。 24 | * 之前,我们已经推荐将 `tsconfig.json` 设为 `“allowSyntheticDefaultImports”: true` 从而在任何地方使用 ES 风格的导入(`import Vue from 'vue'`)。 新的输入将正式转换为ES风格的导入/导出语法,因此不再需要配置,并且用户在所有情况下都需要使用ES风格的导入。 25 | * 为了配合导出语法的改变,以下依赖于 Vue 核心输入的核心库 `vuex`, `vue-router`, `vuex-router-sync`, `vue-class-component` 将会收到新的主要版本,并且应与 Vue 核心 2.5 一起升级。 26 | * 当执行自定义模块扩充时,用户应该使用 `interface VueConstructor` 而不是 `namespace Vue`。(example diff) 27 | * 如果使用 `ComponentOptions ` 对组件选项进行注释,则此类型的 `computed`,`watch`,`render` 和生命周期钩子将需要手动类型注解。 28 | 29 | 我们尽力减少所需的升级工作,这些类型的改进与 `vue-class-component` 中使用的基于类的 API 兼容。 对于大多数用户来说,只需升级依赖并切换到ES风格的导入即可。 同时,我们还建议你将Vue 版本锁定到2.4.x,直到你准备升级为止。 30 | 31 | ## 未来规划:vue-cli中的TypeScript支持 32 | 33 | 2.5之后,我们计划在下一个版本的 vue-cli 中引入对TypeScript 的官方支持,以便使 TS + Vue 用户更轻松地启动新项目。 敬请关注! 34 | 35 | ## 对于非TypeScript用户 36 | 37 | 这些更改不会以任何负面的方式影响非 TypeScript Vue 用户; 根据公共JavaScript API,2.5 将完全向后兼容,并且TypeScript CLI集成将完全选择加入。 但是如上所述,如果你使用[vue-language-server](https://github.com/vuejs/vetur/tree/master/server)强大的编辑器扩展,则会注意到更好的自动完成建议。 38 | 39 | — 40 | 41 | 感谢 [Daniel Rosenwasser](https://github.com/danielrosenwasser), [HerringtonDarkholme](https://github.com/HerringtonDarkholme), [Katashin](https://github.com/ktsn) 以及 [Pine Wu](https://github.com/octref) 对于这些特性的工作以及对这篇文章的审阅。 42 | -------------------------------------------------------------------------------- /送给 ES6 开发者的7个hack .md: -------------------------------------------------------------------------------- 1 | > 原文:[7 Hacks for ES6 Developers](https://medium.com/dailyjs/7-hacks-for-es6-developers-4e24ff425d0b) 2 | > 3 | > 译者:[madneal](https://github.com/madneal) 4 | > 5 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 6 | > 7 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 8 | 9 | 10 | ![](https://cdn-images-1.medium.com/max/9900/1*xmqGcZXL4t7mJoG1SBvErA.jpeg) 11 | 12 | 13 | 关注原来的 [JavaScript hacks](https://hackernoon.com/javascript-hacks-for-hipsters-624d50c76e8e),上面有一些新的好东西。*2018 使用 JavaScript 写代码真的又变得有意思了!* 14 | 15 | ![](https://cdn-images-1.medium.com/max/2000/1*4877k4Hq9dPdtmvg9hnGFA.jpeg) 16 | 17 | ## Hack #1 — 交换变量 18 | 19 | 使用数组结构来交换值 20 | 21 | let a = 'world', b = 'hello' 22 | [a, b] = [b, a] 23 | console.log(a) // -> hello 24 | console.log(b) // -> world 25 | 26 | // 是的,很神奇 27 | 28 | ## Hack #2 — 使用解构的 Async/Await 29 | 30 | 再说一遍,数组结构真的很棒。通过和 async/await 以及 promise 结合可以让复杂的流程变得简单。 31 | 32 | const [user, account] = await Promise.all([ 33 | fetch('/user'), 34 | fetch('/account') 35 | ]) 36 | 37 | ## Hack #3 — 调试 38 | 39 | 对于那些喜欢使用 console.logs 来调试的人来说,现在有一些特别酷的(并且我也听说过 console.table): 40 | 41 | const a = 5, b = 6, c = 7 42 | console.log({ a, b, c }) 43 | 44 | // 输出优雅的对象: 45 | // { 46 | // a: 5, 47 | // b: 6, 48 | // c: 7 49 | // } 50 | 51 | ## Hack #4 — 一行搞定一切 52 | 53 | 对于数组操作,语法可以非常紧凑 54 | 55 | // 寻找最大值 56 | const max = (arr) => Math.max(...arr); 57 | max([123, 321, 32]) // outputs: 321 58 | 59 | // 对数组求和 60 | const sum = (arr) => arr.reduce((a, b) => (a + b), 0) 61 | sum([1, 2, 3, 4]) // output: 10 62 | 63 | ## Hack #5 — 数组拼接 64 | 65 | 拓展操作符可以用来代替 concat: 66 | 67 | const one = ['a', 'b', 'c'] 68 | const two = ['d', 'e', 'f'] 69 | const three = ['g', 'h', 'i'] 70 | 71 | // 老方法 #1 72 | const result = one.concat(two, three) 73 | 74 | // 老方法 #2 75 | const result = [].concat(one, two, three) 76 | 77 | // 新方法 78 | const result = [...one, ...two, ...three] 79 | 80 | ## Hack #6 — 克隆 81 | 82 | 轻松克隆数组和对象: 83 | 84 | const obj = { ...oldObj } 85 | const arr = [ ...oldArr ] 86 | 87 | 注意:这会产生一个浅克隆。 88 | 89 | ## Hack #7 — 命名参数 90 | 91 | 通过结构让函数以及函数函数调用更具有可读性: 92 | 93 | ```javascript 94 | const getStuffNotBad = (id, force, verbose) => { 95 | ...do stuff 96 | } 97 | const getStuffAwesome = ({ id, name, force, verbose }) => { 98 | ...do stuff 99 | } 100 | 101 | // 在代码的其它某个地方... 到底什么是 true, true? 102 | getStuffNotBad(150, true, true) 103 | 104 | // 在代码的其他某个地方.. I ❤ JS!!! 105 | getStuffAwesome({ id: 150, force: true, verbose: true }) 106 | ``` 107 | 108 | ![](https://cdn-images-1.medium.com/max/2048/1*ZrJKJqBsksWd-8uKM9OvgA.png) 109 | 110 | **已经全部知道了?** 111 | 112 | 你是一个真正的黑客,让我们继续在 Twitter上的谈话你还可以看看我的 [Torii](https://toriihq.com) 教学,我们让“SaaS 头痛”消失。 113 | -------------------------------------------------------------------------------- /🚀 宣布 Parcel:一个快速,零配置的 Web 应用打包工具 📦.md: -------------------------------------------------------------------------------- 1 | ## 🚀 宣布 Parcel:一个快速,零配置的 Web 应用打包工具 📦 2 | 3 | >原文:[🚀 Announcing Parcel: A blazing fast, zero configuration web application bundler 📦](https://hackernoon.com/announcing-parcel-a-blazing-fast-zero-configuration-web-application-bundler-feac43aac0f1) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 今天,我非常高兴地宣布 Parcel,一个快速,零配置的 Web 应用程序打包工具,我对于该工具的工作已经持续了几个月。 去 [Github](https://github.com/parcel-bundler/parcel)上看看吧! 12 | 13 | ![](https://cdn-images-1.medium.com/max/5994/1*Gjhk6qvPM5zAy1iPPS1ttg.png) 14 | 15 | 为了解决我在 Browserify 和 Webpack 等现有模块打包工具中遇到的两个主要问题:**性能**和**配置经验**,我开始研究 Parcel。 16 | 17 | ### 特性 18 | 19 | * 🚀 **非常快**的打包时间 - 多核编译,以及文件系统缓存,这样即使在重新启动后也能快速重建。 20 | * 📦对于 JS, CSS, HTML, 图片以及文件资源以及其它支持[开箱即用](https://parceljs.org/assets.html),**不需要安装插件**。 21 | * 🐠在需要时使用 Babel,PostCSS 和 PostHTML **自动**[**转换**](https://parceljs.org/transforms.html)**模块** - 甚至是node_modules。 22 | * ✂️ **零配置**[代码分割](https://parceljs.org/code_splitting.html)使用动态import() 语句。 23 | * 🔥内置支持[热加载](https://parceljs.org/hmr.htm) 24 | * 🚨 友好的错误日志体验 - 语法高亮显示的代码帧有助于查明问题。 25 | 26 | ### 性能 27 | 28 | 我被激发建立一个新的打包工具的第一个原因是性能。 我已经在数千个模块上做了一些相当大的应用程序,并且总是对现有打包工具的速度感到失望。 大型应用程序可能需要几分钟才能完成,这在开发过程中尤其令人沮丧 29 | 30 | 许多打包工具专注于快速增量重新构建性能,这是很好的。 但是,最初的构建性能对于开发和生产/ CI 构建也非常重要。 31 | 32 | Parcel 通过使用工作进程**并行编译代码**,利用现代多核处理器解决了这个问题。 这导致了初始构建的巨大加速。 它还有一个文件系统缓存,可以保存每个文件的编译结果,以便更快的后续启动。 33 | 34 | ![Based on a reasonably sized app, containing 1726 modules, 6.5M uncompressed. Built on a 2016 MacBook Pro with 4 physical CPUs.](https://cdn-images-1.medium.com/max/2000/1*t8afejIByMpoZKSs-URTIQ.png) 35 | 36 | ### 零配置体验 37 | 38 | 我建立Parcel的第二个原因是帮助解决管理配置的痛苦。大多数其它打包工具都是围绕着配置文件以及大量的插件建立起来的,为了使事情顺利进行,看到 500 行以上的应用程序配置并不罕见。 39 | 40 | 这种配置不仅繁琐耗时,而且很难正确使用,并且必须针对每个应用程序进行复制。通常情况下,这可能导致次优化的应用程序转到到生产。 41 | 42 | Parcel 被设计为**零配置**:只需将它指向你的应用程序的入口点,它就能正确工作。 Parcel 支持 JS,CSS,HTML,图片,文件资源等等 - 不需要任何插件。 43 | 44 | Parcel 的零配置体验也涉及到文件格式。当 Parcel 检测到 .babelrc,.postcssrc 等时,也会自动应用像 Babel,PostCSS 和 PostHTML 这样的**转换**。这甚至适用于仅用于该模块的 node_modules 中的第三方代码,因此应用程序作者不需要知道如何构建他们导入的每个模块,并且构建不会减慢不必要地在每个文件上运行 Babel。 45 | 46 | 最后,还支持代码分割和热模块重新加载等高级打包功能。在生产模式下,Parcel 自动启用缩小,未来还会进行其他优化,如 tree-shaking。 47 | 48 | ### 未来架构 49 | 50 | 启动一个新项目的一个好处是,我能够为 Parcel 设计一个更加现代化的架构,这个架构更加可扩展,更灵活,同时无需用户配置,并支持**代码拆分**和**热加载**等高级功能。 51 | 52 | 大多数打包工具主要关注 JavaScript,并支持其他格式。例如,默认情况下,其他文件类型通常会内嵌到JavaScript 文件中,并使用额外的插件和 hack 将其再次提取到单独的文件中。 53 | 54 | 在 Parcel 中,任何类型的文件都可以成为一等公民。添加代表输入文件的新资源类型和将类似类型的资源组合到输出文件中的打包工具很容易。 55 | 56 | 例如,分析和生成 CSS 代码的 CSS 资源类型和将 CSS 资源组合成最终打包的 CSS Packager。 JS,HTML 等存在类似的类型。这样,Parcel 完全是**文件类型无关**的。 57 | 58 | 你可以阅读更多关于[Parcel 如何在网站上工作](https://parceljs.org/how_it_works.html)的信息。 59 | 60 | ### 试试把 61 | 62 | Parcel 刚刚开始,但许多应用程序已经开箱即用并且零配置! 所以试试看吧 - 删除你的webpack/browserify配置,卸载这些插件,然后尝试Parcel。😎 63 | 64 | 欢迎向我反馈! 你可以在Twitter上找到我[@devongovett](https://twitter.com/devongovett)。 65 | 66 | * [网站和文档](https://parceljs.org) 67 | 68 | * [Github](https://github.com/parcel-bundler/parcel) 69 | -------------------------------------------------------------------------------- /10个开发新手应该熟悉的github仓库.md: -------------------------------------------------------------------------------- 1 | # 10个开发新手应该熟悉的github仓库 2 | 3 | >原文:[The 10 GitHub repos new developers mention the most](https://medium.freecodecamp.com/the-10-github-repos-people-mention-the-most-in-freecodecamps-main-chat-room-189750600fa4) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![github](https://cdn-images-1.medium.com/max/2000/1*QUPbzsIyIs3QLx6LjGlgPw.jpeg) 12 | 13 | freeCodeCamp 社区每一周都会产生大量的数据。这个社区最活跃的一部分就是它的聊天系统。成千上万的人会在里面讨论,聊科技并且互相帮助来提高他们的编程技术。 14 | 15 | 我经常会对这些数据感到疑问。这个礼拜,我很好奇哪一些github仓库人们是觉得和它们学习最为相关的。我从freeCodeCamp[主聊天室](https://gitter.im/freecodecamp/freecodecamp)分析除了大量的聊天历史纪录。 16 | 17 | 在上述提到的仓库之中,下面是社区中提及最多的10个仓库: 18 | 19 | ## [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) 20 | 21 | 你可能会看到这个首当其冲。但是这并仅仅是因为这是我获取数据的来源。freeCodeCamp学习平台本身就十分受欢迎,将近25,000star,超过1,000fork,每一周都会产生大量的issue和pr。 22 | 23 | 因此,人们在聊天室会经常提到这个。 24 | 25 | #### [getify/You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS) 26 | 27 | Kyle Simpson 的 You Don’t Know JavaScript这本书毫无疑问是freeCodeCamp社区非官方的参考书籍。[Kyle](https://medium.com/@getify)现在也为另外一个类似的项目YDKJS工作,**“Functional Light JS”**,这个也渐渐地被提及地越来越多。 28 | 29 | #### [vhf/free-programming-books](https://github.com/vhf/free-programming-books) 30 | 31 | 一个经常更新的免费资源列表。这个仓库收集了来自于世界各地的材料,并且组织的很有条理。这个仓库包括数据,播客,网站,开发工具等等,只要你能想到的。绝对是学习编程的人必须要看的。 32 | 33 | #### [twbs/bootstrap](https://github.com/twbs/bootstrap) 34 | 35 | Bootstrap的github账户,非常知名的web响应式设计框架。这个仓库提供了许多技术信息,但是同时也具有很多其他有用网站的链接。如果你在寻找更多的这个框架的文档信息,你可以访问[getbootstrap.com](https://getbootstrap.com/)。 36 | 37 | #### [jwasham/coding-interview-university](https://github.com/jwasham/coding-interview-university) 38 | 39 | [Googley as Heck](https://medium.com/@googleyasheck) 创建这个仓库的目的是为了[他准备谷歌面试8个月的过程](https://medium.freecodecamp.com/why-i-studied-full-time-for-8-months-for-a-google-interview-cc662ce9bb13)的相关文档。它包含了为了通过谷歌非常知名的白板测试需要准备的详细列表,以及解释多种计算机科学概念的参考链接。(值得一体的是,在做了以上的准备之后[他最后还是去了亚马逊](https://medium.freecodecamp.com/ive-been-hired-by-amazon-8b21f7c27de5#.6e1kc7fes)。 40 | 41 | #### [ericelliott/essential-javascript-links](https://github.com/ericelliott/essential-javascript-links) 42 | 43 | [Eric Elliott](https://medium.com/@_ericelliott)的JavsScript链接仓库很长一段时间都是freeCodeCamp社区里面最后欢迎的资源列表之一。(他最近被[vhf/free-programming-books](https://github.com/vhf/free-programming-books)挤下来了。)它是一个综合列表,尽管在撰写本文的时候,这个仓库已经2年没有更新了。但是这个仓库对于JavaScript学习者来说依然是一个很好的参考。 44 | 45 | #### [d3/d3](https://github.com/d3/d3/wiki) 46 | 47 | 如果你想学习d3.js,那么官方的github仓库无疑是开始学习最好的地方。在freeCodeCamp里面提到里面最多的两块是在它的wiki里面: 48 | 49 | - [the gallery](https://github.com/d3/d3/wiki/Gallery) 50 | - [the tutorials](https://github.com/d3/d3/wiki/Tutorials) 51 | 52 | 这些包含了很好的信息,也包含你在学习d3.js需要的参考列表。 53 | 54 | #### [vinta/awesome-python](https://github.com/vinta/awesome-python) 55 | 56 | 作为“精心设计的 Python 框架,库,软件和资源列表”,如果你希望在Python中获得更好的结果,这是一个很好的开始。 57 | 58 | #### [oneuijs/You-Dont-Need-jQuery](https://github.com/oneuijs/You-Dont-Need-jQuery) 59 | 60 | 这是一个致命的仓库使用原生的JS去解决典型的编程问题。这个仓库的兴起和React的发展密切相关。 61 | 62 | #### [toddmotto/public-apis](https://github.com/toddmotto/public-apis) 63 | 64 | 一个很好并且经常更新的公共API集合。这个API仓库设置分为好几类,这使得搜索变得更为简单。 65 | 66 | 67 | 68 | 如果你想知道的话,所有的数据都是从2016年6月到2017年3月之间的freeCodeCamp的[main Gitter chatroom](https://gitter.im/FreeCodeCamp/FreeCodeCamp) 获取的。我通过运行一个Python脚本来获取这区数据,然后根据提及的数量来评估最近提到的github链接。我做的最后的选择是基于选择性。 69 | 70 | 同样,这个列表只是冰山一角。 freeCodeCamp的社区每天引用数百个仓库。 71 | 感谢阅读,快乐编程! 72 | 73 | -------------------------------------------------------------------------------- /2019年针对API安全的4点建议.md: -------------------------------------------------------------------------------- 1 | ## 2019 年针对 API 安全的 4 点建议 2 | 3 | > 原文:[4 Tips for Better API Security in 2019](https://medium.com/apis-and-digital-transformation/4-tips-for-better-api-security-in-2019-7d3a3b852a45) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | [![kMqL3d.md.png](https://s2.ax1x.com/2019/01/29/kMqL3d.md.png)](https://imgchr.com/i/kMqL3d) 12 | 13 | 无论是在[科技](https://www.darkreading.com/application-security/expect-api-breaches-to-accelerate/d/d-id/1332504)[媒体](https://securityboulevard.com/2018/12/2018-sees-api-breaches-surge-with-no-relief-in-sight/)亦或是[分析报告](https://www.gartner.com/doc/3834704/build-effective-api-security-strategy)中,2018年 “API”以及“安全”变得越来越常见,-或者更糟糕,“API” 以及“违规”[一起出现在头条中](https://www.securityweek.com/next-big-cyber-attack-vector-apis)。 14 | 15 | APIs(应用程序编程接口)不仅是应用程序,系统和数据之间的连接组织,而且是允许开发人员利用和重用这些数字资产以实现新目的的机制。API 几乎影响到每个数字用例,它们在安全新闻中的作用不仅仅是 API 中的一个内在缺陷,因为它们中的一些已被破解,因此存在明显的缺陷。 16 | 17 | 但是头条新闻强调了一个重要信息:如果 API 安全性不是企业 2019 年优先事项的首要事项,那么优先级列表就不完整。 18 | 19 | 实际上,API 安全的要求正在成为一种共识: 20 | 21 | * 在 2017 年 12 月的报告“[如何构建有效的API安全策略](https://www.gartner.com/doc/3834704/build-effective-api-security-strategy)中,”Gartner 分析师 Mark O'Neill, Dionisio Zumerl e和 Jeremy D'Hoinne 预测,“2022年,API 滥用将是最常见的攻击向量,导致企业网络应用程序的数据泄露。” 22 | 23 | * [OWASP Top 10](https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf.pdf)是一个备受推崇的 Web 安全威胁列表,其中多次提及 API。其明确的警告包括针对没有保护即传输敏感数据的 API 的警告,针对可疑行为而未监控流量的 API 以及使用易受攻击组件的 API。 24 | 25 | * 医疗保健组织 HIMMS [发布报告](https://www.hipaaguide.net/api-vulnerabilities-and-usb-related-cyberattacks-identified/)详细说明了 2018 年风险不安全的 API 可能对敏感的医疗保健数据造成的影响。 26 | 27 | 调查显示企业已经[特别关注](https://www.slideshare.net/Imperva/api-security-survey?qid=aab26aae-da6c-40b0-8c28-0ea3a0f526a8&v=&b=&from_search=4)关于威胁机器人和分布式拒绝服务(DDoS)攻击代表 API。 尽管存在这些关注,但攻击风险仍然存在 - 特别是当企业缺乏对其 API 如何被利用的洞察力时。许多组织甚至仍然不知道他们部署了多少 API,是否有人使用 API,或者 API 是否正在推动流量。 28 | 29 | 当然,与 API 相关的违规和安全事件的数量越来越多,证明了 API 安全的重要性。 一个[政府机构的脆弱性](https://krebsonsecurity.com/2018/11/usps-site-exposed-data-on-60-million-users/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+KrebsOnSecurity+%28Krebs+on+Security%29)允许任何登录用户不恰当地查询系统以获取其他用户的私人详细信息,包括电子邮件地址,电话号码和街道地址。其他机构已经暴露了更敏感的数据。它们所带来的漏洞和损害各不相同 - 但重点是,依靠设计糟糕且管理不善的 API 可能会随着时间的推移风险越来越大 30 | 31 | 企业应如何应对这一日益严重的威胁 以下是 Google Cloud 的 Apigee 团队推荐的四个建议。 32 | 33 | ## 以 TLS 为基础 34 | 35 | * “传输层安全性”或 TLS 加密流量,有助于确保客户端与正确的服务器通信,并且是 API 安全性的基础。API 不应该没有它。 36 | 37 | * 跟上 TLS 的变化 - 因为它们很常见。许多 API 团队使用 Qualisys SSL Labs 的 [SSL Server Test](https://www.ssllabs.com/ssltest/) 等服务测试 TLS 配置。 38 | 39 | * 考虑使用跟踪工具,数据屏蔽和标记化来除了加密。 40 | 41 | ## 专注于身份验证 42 | 43 | * 控制 API 访问的能力是有效 API 安全性的基石。 企业应使用 OAuth 对用户进行身份验证。 44 | 45 | * 验证终端用户以及应用的身份。 46 | 47 | ## 使用速率限制来防止暴力攻击并管理流量 48 | 49 | * 使用速率限制来防止暴力攻击。例如,黑客可能会使用自动化软件通过系统猜测密码来生成大量连续登录尝试。如果 API 不受速率限制的保护,则可能允许此攻击无限期地继续或直到成功为止。 50 | 51 | ## 使用行为模式和机器学习将坏机器人放在适当位置 52 | 53 | * 不仅监控 API 访问,还监控流量模式,以发现可疑行为。 54 | 55 | * 应用复杂的算法和机器学习来发现坏机器人,并注意适用于网络或 Web 攻击的防御方法可能对 API 无效。 56 | 57 | 58 | 企业 IT 中为数不多的确定的事情之一是,只要企业使用技术,坏的参与者就会试图找到漏洞。挑战很多,但它们也是[成功的一个不可避免的一部分](https://www.rtinsights.com/with-apis-dealing-with-bad-bots-is-the-cost-of-success/ ),随着公司的数字化越成功,它可能吸引的攻击者就越多。 59 | 60 | 61 | 以上建议是一个起点,但企业需要积极主动,始终意识到在为开发人员提供用户友好的 API 以及保护其免受攻击者攻击之间保持平衡,这是一个微妙而迭代的过程。 除了技术方面的考虑之外,还有安全的人性方面 - 企业围绕其 API使 用的服务条款,它传递 API 变更或响应违规的方式等。 62 | 63 | 虽然没有自满的余地,但企业不会被不良行为者所俘虏,也不会越来越复杂。如果企业对 API 安全保持合适的关注,那么将会尽可能地确保2019年 那些 API 安全地头条将会是*其它*公司的违规。 64 | 65 | **[对管理API和推动数字业务的更多提示感兴趣? 请参阅 Apigee 的新电子书,“[API产品思维模式](https://pages.apigee.com/apis-products-register.html?utm_source=medium&utm_medium=article&utm_campaign=apis-products-microsite)。”]** 66 | -------------------------------------------------------------------------------- /Vue in 2016.md: -------------------------------------------------------------------------------- 1 | # Vue in 2016 2 | 3 | ![vue trend](https://cdn-images-1.medium.com/max/800/1*ZJD3llCWveVH9-uUcCjMCw.png) 4 | 5 | 现在已经是2016的尾声了!在这过去的12个月里,Vue的持续增长速度已经超过了我的预期--这个项目已经从一个相对较小的小框架成长起来,现在已经被用来和这个领域最出名的框架相比较。让我们看看都发生了什么吧! 6 | 7 | ## 2016 统计总览 8 | 9 | * NPM 下载量: 1,943,567 total, 1,531,217 YTD (up from 382,184 in 2015, +300%) 10 | * 核心GitHub仓库star数: 37,664 total, ~26,000 YTD (up from ~7,600 in 2015, +240%) 11 | * 核心仓库pull request合并数: 350 total, [258 YTD](https://github.com/vuejs/vue/pulls?utf8=%E2%9C%93&q=is%3Apr%20is%3Amerged%20merged%3A2016-01-01..2016-12-31%20) (up from [70](https://github.com/vuejs/vue/pulls?utf8=%E2%9C%93&q=is%3Apr%20is%3Amerged%20merged%3A2015-01-01..2015-12-31%20) in 2015, +268%) 12 | * vuejs.org网页浏览数: 21,424,759 YTD (up from 3,761,728 in 2015, +470%) 13 | * Chrome开发者工具周活跃用户: 84,098 (去年没有数据统计) 14 | 15 | [Trivia: Vue是Github上面Javascript项目star数目前十,并且是2016年所有项目中的第三名](https://docs.google.com/spreadsheets/d/11bGpZq6ixlhrmQnzEUqbgbwTQwQVdtvILjp32vaOKBc/edit#gid=1735042899)* (是第一名在源代码项目中).* 16 | 17 | ## 这会仅仅就是个炒作吗? 18 | 19 | 我们当然希望不是!Vue现在已经开始差不多3年的时间了,并且在这过去的两年中增长曲线已经保持稳定。我们在我们将Vue用于产品的用户中收到了积极的反馈,今年在HN-front-page上已经有两名Vue用户在文章上表达了积极的意见。上面说,Vue不是也不打算成为下一个闪亮的东西你应该尽快向其发展--它的设计目的不是解决UI的开发范例;而是它是能够使更多的人可以来建设网站。Vue受到很多其他的完美的框架所激励,但是它的目标是结合并且以分享这些想法,并且这个过程是循序渐进的,因此更多的开发者从中受益。因此不要因为它很流行就向其转换--但是你应该尝试一下来看一下它能否让你成为一个更加快乐的开发者! 20 | 21 | ### 变得独立 22 | 23 | 在三月份初我决定为Vue独立全职工作,并且启动了 [Patreon campaign](https://www.patreon.com/evanyou),这个活动到目前为止都是很成功的,这一点其实我也很意外。这是我第一次不需要向经理报告而独自工作,这是一次全新自由的经历。好的方面是工作再也感觉不是工作了:我不需要强迫自己去工作,因为我需要做的正是我想做的,并且我能够完全控制如何并且何时开始工作。另外一个方面,它也是坏的方面:在生活和工作中平衡变得很困难,特别是作为一个新爸爸(今年我也有了一个新宝宝!)这也正是我学着处理的事情并且希望明年可以变得更好。但是总而言之,我觉得我现在更有动力和成就感,我想向所有的Patreon backers和赞助者表示感谢。 24 | 25 | ### 发布 2.0 26 | 27 | 2.0的工作是一个大的工程--为此我已经考虑了很长的时候,但是得益于全职工作的转换我才有时间开展这项工作。得益于编译/渲染的策略,这整个项目被从头到尾重写了--但是同时也要保持同样的开发体验并且API的调用也应该和之前版本差不多。这意味着我们必须对vue-router,vuex以及build工具链的相关的生态系统来对新的核心工作,并且更新了相应的所有文档。这其实涉及到更多我参与的工作:我在四月初开始了Vue 2.0的原型,[官方发布](https://medium.com/the-vue-point/vue-2-0-is-here-ef1f26acf4b8#.2ptwit6jz)实在九月三十号,差不多有六个月的时间!新的发布让Vue具有新特性和跨环境能力的同时,也使它的体积更小,更快捷并且更强大,回顾过去,我对我们完成的工作感到很骄傲。 28 | 29 | ### 不再是一个个人项目 30 | 31 | 在Vue相关拓展的项目中,我有幸和社区中的很多杰出的贡献者一起合作。今天,很多[核心团队成员](https://github.com/orgs/vuejs/people)都对这个项目的各个方面做出了贡献,从核心功能比如服务端的渲染到子项目比如文档工作(vuejs.org),vue-router,vuex以及官方Typescript的集成。他们对开源工作的激情和奉献让我自惭形秽。 32 | 33 | 当然,同样感谢所有其他参与讨论设计,提出新功能,issue分类并且提交BUG修复的社区贡献者。我们收到越来越多的PR(今年核心项目就有258个!)Vue生态系统通过综合大家共同的努力从而使这个生态系统变得越来越好。这个项目如果没有大家的努力也没有办法发展至今! 34 | 35 | ### 未来展望 36 | 37 | 对于Vue还有很多方面可以进一步提升。现在让我们看看2017的清单有哪些: 38 | 39 | #### 提高测试需求 40 | 41 | 根据推特上的反馈,很多用户反映Vue的组件和应用的测试信息还不够充分。这一领域毫无疑问我们会专注提升--不仅提供更多的文档指导,并且提供更多的官方测试单元从而使Vue组件测试变得更加容易。 42 | 43 | #### 改善开发体验 44 | 45 | 我们想进一步提升开发体验:更好的开发建议和警告,更好的服务端渲染堆栈,开发者工具中更好的性能日志,以及更好的CLI模板从而更容易使用服务端渲染或者PWA。 46 | 47 | #### 对于生态系统更好的可发现性 48 | 49 | Vue的生态系统成长迅速,从而[awesome-vue](https://github.com/vuejs/awesome-vue)变得很难浏览和评价。团队已经在努力考虑这个问题,并且我们正在通过一个项目来帮助用户识别高质量的社区项目;对于每一个包含的项目都会有更高标准并且提供更多的信息。 50 | 51 | #### 原生渲染 52 | 53 | 和阿里巴巴合作的[Weex project](http://weex-project.io/)已经取得实质性的进展。我们的第一个主要目标--在最近的0.9.4发布的版本中通过Weex的原生渲染引擎使得Vue 2成为真正的Javascript的实时框架。在2017年会对文档进行修补,通过社区的反馈和阿里巴巴的大规模使用来改进使用体验和API。 54 | 55 | #### 拥抱Web平台特色 56 | 57 | 新的标准出现并且得以实现,我们密切关注能够潜在为Vue带来有意义进步的新的标准。比如,可能通过 [ES2015 Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)来消除Vue响应系统当前的限制。我们也在探索将Vue组件编译并且发布成原生的自定义元素。马上,最大的苦难是浏览器的兼容性--为了在所有支持的浏览器中保持一致的表现,我们只有在支持比例达到一定的程度才会发布这些新特色。但是其他出现的标准我们已经注意到并且在试验环节。如果实际成熟,Vue会快速地兼容这些新的标准。 58 | 59 | #### 还有一点:我们在2017年有一个会议啦! 60 | 61 | 当然实际尚早,但是浏览这个[网站](http://conf.vuejs.org/)并且参与[调研](https://docs.google.com/forms/d/e/1FAIpQLSfiRF9JIpvAcWL7EsnpODIhf_JiNX3PETA_S3XnqmtuG2foQA/viewform))将会使得这件事变得更加有意义。更好的是,如果你能提交一个[演讲](https://docs.google.com/forms/d/e/1FAIpQLSdtbxBpV0j_zCnELXQuIkeGH8x6gaOWE0J8tTsAdpa0O5MYOw/viewform)来分享你的知识和经历。 62 | 63 | 如果你对Vue感兴趣的话,那么你可以从[官方网址](https://vuejs.org/)开始,你也可以在[推特](https://twitter.com/vuejs)上关注我们!(然而我们有墙!!!) 64 | 65 | -------------------------------------------------------------------------------- /你可能不知道谷歌浏览器开发工具的其他用处.md: -------------------------------------------------------------------------------- 1 | > 原文:[你可能不知道谷歌浏览器开发工具的其他用处](https://medium.freecodecamp.com/10-tips-to-maximize-your-javascript-debugging-experience-b69a75859329#.20eb3ho5g) 2 | > 3 | > 译者:[madneal](https://github.com/madneal) 4 | > 5 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 6 | > 7 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 8 | 9 | ## 你可能不知道谷歌浏览器开发工具的其他用处 10 | 11 | Chrome内嵌开发者工具。它具有丰富的功能特色,比如元素,网络以及安全。今天,我们将完全关注javascript的console. 12 | 13 | 当我才开始编程的时候,我只是将console用作纪录服务器的响应。但是后来经过一些教学的帮助,我开始发现console可以做的更多。 14 | 15 | 在这我们讲一些你可以用console做更多有用的事情。如果你是用chrome浏览这篇文章,你可以马上就试试效果。 16 | 17 | ### 1. 选择节点元素 18 | 19 | 如果你熟悉jquery的话,你应该知道`$('.class')`和`$('#id')`事多的么的重要。你可以根据id或者类名选择相应的元素。 20 | 21 | 同样你可以在console使用同样的方式来访问元素。`$('tagName') $('.class') $('#id')`和`document.querySelector('')`是等同的。这个将返回文档中第一个匹配这个选择器的元素。 22 | 23 | 你可以用`$$('tagName') `来访问,注意这边的两个美元符号可以访问所有符合这个选择器的元素。这些元素会组成一个数组 24 | 25 | ![developer console](https://d262ilb51hltx0.cloudfront.net/max/1200/1*x-ygabMZbtYHH0mhGVaWbQ.png) 26 | 27 | 28 | 29 | 30 | 31 | ### 2.将你的浏览器转化成一个编辑器 32 | 33 | 你是否想过可以直接在浏览器中直接编辑?答案是肯定的,你可以将你的浏览器转化成一个文本编辑工具。你可以在dom元素中任意添加或者删除文本。 34 | 35 | 你不需要检测html中的元素。取而代之,你只要去console里面输入以下: 36 | 37 | ```document.body.contentEditable = true``` 38 | 39 | 40 | 41 | ### 3.寻找dom中元素绑定的事件 42 | 43 | 当调试的时候你可能希望知道dom元素中绑定的事件。console工具能使你很轻松就找到这些事件。`getEventListeners($('selector'))`将会返回一个数组包含所有事件的对象。你可以展开这个对象看到所有的事件: 44 | 45 | ![events](https://d262ilb51hltx0.cloudfront.net/max/1200/1*ZYcW2PoXTIjz3oAUmdu58w.png) 46 | 47 | 48 | 49 | 如果希望找到某个特定事件的监听,你可以这么做: 50 | 51 | ```getEventListeners($('selector')).eventName[0].listener``` 52 | 53 | 这将展示所有和这个事件相关的监听。比如: 54 | 55 | ```getEventListeners($('.firstName')).click[0].listener``` 56 | 57 | 58 | 59 | ### 4.监听事件 60 | 61 | 如果你想监听特定元素绑定的事件的时候,你也可以在console里面这么做。你可以使用以下的这些命名: 62 | 63 | * `monitorEvents($('selector'))`将会监听符合这个选择器的元素的所有事件,并且将会显示这些事件当事件被触发的时候。 64 | * `monitorEvents($('selector'),'eventName')`将会监听符合这个选择器的特定事件。你可以将事件的名称作为一个参数传入到这个函数中。 65 | * `monitorEvents($('selector'),['eventName1','eventName2'….])`将会监听符合这个选择器的事件。 66 | * `unmonitorEvents($('selector'))`这个会停止监听并且在console里面显示出所有的事件。 67 | 68 | 69 | 70 | ### 5.找到语句块执行的时间 71 | 72 | console里面有一个很重要的函数叫做`console.time('labelTime')`能够启动一个计时器。另外又一个函数叫做`console.timeEnd('labelName')`能够结束相应的计时器。 73 | 74 | 比如我们想看到一个循环的执行时间,我们可以做如下处理: 75 | 76 | ```javascript 77 | console.time('myTime'); //Starts the timer with label - myTime 78 | 79 | for(var i=0; i < 100000; i++){ 80 | 2+4+5; 81 | } 82 | 83 | console.timeEnd('mytime'); //Ends the timer with Label - myTime 84 | 85 | //Output - myTime:12345.00 ms 86 | ``` 87 | 88 | 89 | 90 | ### 6.将变量的值以表格形式呈现 91 | 92 | 当我们有如下的一个数组的时候: 93 | 94 | ``` 95 | var myArray=[{a:1,b:2,c:3},{a:1,b:2,c:3,d:4},{k:11,f:22},{a:1,b:2,c:3}] 96 | ``` 97 | 98 | 我们可以使用`console.table(variableName)`从而以表格的形式更好地展现数据的属性。 99 | 100 | ![table](https://d262ilb51hltx0.cloudfront.net/max/1200/1*ODDvO9nnwEWyl1OqaZwifw.png) 101 | 102 | 103 | 104 | ### 7.在dom中检测元素 105 | 106 | 你可以直接在console里面检测元素: 107 | 108 | * `inspect($('selector'))`将会检测符合这个在选择器的元素并且会跳转到匹配这个选择器的dom中。 109 | * `$0,$1,$2`能够帮助你检测最近检测过的元素。 110 | 111 | 112 | 113 | ### 8.列出与纳素的属性 114 | 115 | 如果你希望列出元素所有的属性,你可以直接在console里面输入`dir($('selector'))`返回dom元素中的相关属性。 116 | 117 | 118 | 119 | ### 9.取到上次最近结果的值 120 | 121 | 你可以把console当作一个计算器来时用。你可以使用`$_`来获取最近的结果。如下所示: 122 | 123 | ``` 124 | 2+3+4 125 | 9 //- The Answer of the SUM is 9 126 | 127 | $_ 128 | 9 // Gives the last Result 129 | 130 | $_ * $_ 131 | 81 // As the last Result was 9 132 | 133 | Math.sqrt($_) 134 | 9 // As the last Result was 81 135 | 136 | $_ 137 | 9 // As the Last Result is 9 138 | ``` 139 | 140 | 141 | 142 | ### 10.清除cosole和缓存 143 | 144 | 如果你希望清除console和它的缓存,你可以输入`clear()`就可以了。 145 | -------------------------------------------------------------------------------- /3-parameters-to-measure-SAST-testing.md: -------------------------------------------------------------------------------- 1 | # SAST 测试中要测量的三个参数 2 | 3 | >原文:[3 parameters to measure SAST testing](https://snyk.io/blog/parameters-to-measure-sast-testing/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 在我们之前的博客中,为什么[你不能仅使用列表、测试套件和基准测试来比较 SAST 工具](https://snyk.io/blog/cant-compare-sast-tools-lists-test-suites-benchmarks/),我们探索了当今常用来评估和比较 SAST 测试工具的各种工具和指标。我们还研究了为什么这些工具可能会产生不一致的结果并且对于评估 SAST 测试工具可能根本不可靠的一些原因。 12 | 13 | 相反,在评估 SAST 测试工具时,你需要考虑 3 个参数: 14 | 15 | accuracy 16 | completeness 17 | any unique additional values 18 | * 准确性 19 | * 完整性 20 | * 任意其它独特价值 21 | 22 | 在本文中,我们将探索这些参数并研究测量它们的方法。在评估 SAST 测试工具时,有两种相关类型的测量 - 定量(意味着结果的数量与“误报”)和定性(特别是语言深度和支持)。 23 | 24 | ## 定量方面 25 | 26 | 以下对准确性和完整性的定义起初有点复杂,因为它们实际上是同一枚硬币的两面。数学上不可能(根据赖斯定理)进行完美的静态程序分析。人们可能会认为增加建议的数量会发现所有可能的问题。可悲的是,这也会将误报 (FPs) 的数量达到干扰让结果无法处理的级别。SAST 测试供应商可以使用一些技巧来改进结果,但在数学上完美是不可能的。 27 | 28 | ### 准确性 29 | 30 | 在 SAST 测试的上下文中,准确性被松散地定义为具有最高数量的 TP(真正类,即实际问题的发现),同时保持最少数量的 FPs(误报,因此是错误的)。 31 | 32 | 准确性尤其重要。高准确率意味着我们可以获得更有价值的结果,以及更少的“噪音”(不相关的、无法操作的报告)。“噪音”也是阻碍开发者使用 SAST 测试产品的第一大因素,这就是为什么准确性越高,整体开发者体验就越令人满意的原因。 33 | 34 | 为了计算准确性,你首先需要对结果进行分类。那么公式就是 TP*100/(TP+FP)。这将产生一个介于 1 到 100 之间的数字。数字越大,准确度越高。例如,找到 140 个 TP 和 40 个 FP 的工具的准确率为 77.7%。 35 | 36 | ### 完整性 37 | 38 | NIST 定义:“完整性,有时称为召回率,作为发现的实际问题 (TP) 与所有可能的问题(TP 和假反例)的衡量标准。完整性越高(达到其理论最大值 1),工具就越能更好地解决代码中的现有问题。”实际上:遗漏的真实问题的数量,即漏报 (FN)。 39 | 40 | 工具越完整,你将拥有更好的可见性和保护。当然,这也可能转化为更多的发现,但再加上高准确率,这些发现中的大多数应该被证明是相关的。话虽如此,这些发现的严重性始终在完整性方面发挥关键作用——如果你试图将噪音降到最低,一千个低严重性的 FN 不一定是坏事。作为一般经验法则,FN 越少越好。重要的是要知道如何删除它们,以免错过实际的漏洞。 41 | 42 | 仅当你知道代码中存在任何漏洞,或者正在比较多个工具并发现结果存在差异时,才能生成此指标。另一个角度是寻找 FN 的严重性,然后专注于更高优先级的。FN 很难测量,因为它们是未知的未知数。取舍是不可避免的。经验表明,在大的项目中,总是需要预估 FN。在网络安全中,通过感觉太安全来放松警惕绝不是一种选择。 43 | 44 | ## 定性方面 45 | 46 | 定性测量着眼于如何处理语言和漏洞支持。正如我们在上一篇博客中所探讨的那样,只使用已知漏洞列表、测试套件和故意存在漏洞的仓库会产生不完整的图景。因此,一个好的 SAST 是超越列表的。 47 | 48 | 这种测量可以进一步分为两个感兴趣的领域:语言/漏洞支持和深度/准确性方法。 49 | 50 | **语言支持是如何确定的?** 51 | 52 | 了解如何为你正在评估的 SAST 确定语言支持的优先级和确定方式非常重要。 53 | 54 | 我们已经知道漏洞列表是不够的。一种更全面的方法是聚合来自多个来源的数据,以创建可靠的语言支持,既能与当今的网络风险保持同步,又能与上下文相关。 55 | 56 | 因此,虽然列表可以作为一种参考,但还有其他资源可供探索: 57 | 58 | * 新闻来源——“趋势”漏洞和新发布的攻击向量更有可能被利用 59 | * 已知漏洞数据库和漏洞利用数据,例如 NVD 数据库和 [Snyk 漏洞数据库](https://security.snyk.io/)。 60 | * 特定语言和框架的最佳实践和上下文 61 | * 零日漏洞研究,如新模式或现有模式 62 | 63 | 在确定在 Snyk Code 中支持哪些语言和框架时,我们使用以上所有内容以及更多内容来构建客户应该关心的最相关问题的列表。 64 | 65 | **语言深度和准确度如何处理?** 66 | 67 | 虽然拥有强大的支持语言和漏洞列表是重要的第一步,但你还必须考虑将这些转化为结果的程度。 68 | 69 | 例如,依靠开源社区构建和推送的几乎没有严格审查流程的新规则的 SAST 容易产生大量误报,并且通常会在不同语言和漏洞之间产生不一致的结果。 70 | 71 | 在 Snyk Code,我们拥有一支由专门的安全研究人员组成的团队,他们不断努力增加对越来越多的语言和漏洞的支持,并通过增加深度和准确性来改进现有支持。 72 | 73 | **SAST的发展速度和维护性是多少?** 74 | 75 | 如上所示,SAST 解决方案的维护和持续开发非常重要。这意味着两个方面:产品的路线图和公司或社区实现它的能力。机器学习的最新进展使得了解它如何在路线图中发挥作用变得很有趣。同样关键的是对现代语言的支持、现代引擎的使用以及支持新语言的速度。 76 | 77 | 其次,了解公司或社区在维护 SAST 知识库方面的能力非常重要。如上所述,安全需要不断观察并对各种来源作出响应。 78 | 79 | ## 把这一切放在一起 80 | 81 | 通过定量评估,你现在想了解该工具在现实世界中的实际表现。如果该工具提供了许多结果(即使是 TP),或者有很多噪音 (FP),那么拥有最好的语言和漏洞支持是不够的。安全专家想要高度的完整性,但开发人员对具体解决的实用建议更感兴趣。因此,重要的是要在建议的数量、优先级和开发团队解决这些问题的能力之间取得平衡。我们的经验和研究表明,向开发人员提供大量建议(尤其是在准确性较低的情况下)会使他们失去动力,实际上会减慢整个过程。 82 | 83 | 从定性的角度来看,我们建议列出你环境中感兴趣的方面,构建矩阵并插入每个竞争对手的值。 84 | 85 | 对于这些量化特征的测量,我们建议选择选择熟悉的真实项目。为了更加方便,我们建议该项目是一个相对中小型的项目。如上一篇博客所述,你应该避免使用故意易受攻击的应用程序,因为它可能不会表明该工具的真正价值。 86 | 87 | 运行 SAST 并收到结果后,就该对它们进行分类了。分类意味着确定某个结果是 TP(真正的问题)还是 FP(不是真正的问题)。SAST 结果通常与上下文相关,这就是为什么充分了解你正在扫描的项目很重要的原因。最后,你的个人专业知识和工作不能被预先准备好的基准结果所取代。 88 | 89 | 最后,你需要根据本文前面提到的公式计算准确性和完整性。 90 | 91 | ## 为什么不简单地收集所有工具并运行它们呢? 92 | 93 | 如上所示,每个工具都添加了 TP 和 FP。因此,尽管简单地使用所有可能的工具是有意义的,但实际上,分离噪音的工作将超过另一个工具所带来的价值。开发人员将需要处理来自不同工具使用不同格式的双重建议,这将产生大量包袱,更不用说运行时约束了。虽然这是获得 FN 和 FP 数量的好方法,但对于连续操作来说并不可行。根据我们的经验,拥有一个对开发人员友好的平台是最重要的。如果你在安全性非常关键或受监管的环境中工作,你可能希望稍后在 CI/CD 流程中添加专用工具。 94 | 95 | SAST 无疑是每个开发人员都应该在他们的“工具箱”中拥有的强大工具,并且可以真正改变你的应用程序安全性。因此,您必须为你和你的组织选择最佳工具。我们希望上面和上一篇博文中概述的信息和步骤可以帮助你做出更明智的决定。 -------------------------------------------------------------------------------- /采用Flow以及TypeScript.md: -------------------------------------------------------------------------------- 1 | ## 采用Flow以及TypeScript 2 | 3 | ### 两个过渡流程之间的比较 4 | 5 | >原文:[Adopting Flow & TypeScript](http://thejameskyle.com/adopting-flow-and-typescript.html) 6 | > 7 | >译者:[madneal](https://github.com/madneal) 8 | > 9 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 10 | > 11 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 12 | 13 | > 和这首歌[**“Cotton Heads” — Caravan Palace**](https://www.youtube.com/watch?v=QNkBLye7xfY)食用本文更佳。 14 | 15 | 让我们想象一个需要采用类型检查的场景。 16 | 17 | 之后我们注意到我们的app出现了很多NaN。我们寻找源头并且找到了下面的代码: 18 | 19 | 20 | ```javascript 21 | // math.js 22 | function square(n) { 23 | return n * n; 24 | } 25 | square("oops"); 26 | ``` 27 | 我们对自己叹了口气,并且决定或许是时候添加一个类型检查了。我们退后一步,看看我们的选项:[Flow](https://flow.org/)或者[TypeScript](http://www.typescriptlang.org/)。 28 | 29 | 这两个工具都有相当简单的文件逐个采用: 30 | 31 | * **Flow:** 在你的文件顶部添加`// @flow` 注释 32 | * **TypeScriptz:** 将.js后缀改成.ts后缀 33 | 34 | 但是让我们一起来比较。 35 | 36 | ### 采用TypeScript 37 | 为了采用TypeScript,我们将首先将math.js重命名成math.ts: 38 | 39 | ```typescript 40 | // math.ts 41 | function square(n) { 42 | return n * n; 43 | } 44 | square("oops"); 45 | ``` 46 | 现在我们运行typescript: 47 | 48 | (no errors) 49 | 没有错误,因为TypeScript需要添加注解到我们的函数在它如下检查类型之前: 50 | 51 | ```typescript 52 | function square(n: number): number { 53 | return n * n; 54 | } 55 | square("oops"); 56 | ``` 57 | 但是没有这些类型,TypeScript将依赖你的配置来做以下两件事之一: 58 | 59 | 1. 隐含地将每个未知类型投射到任何一个。 这种任何类型将选择您退出所有类型检查。 60 | 2. 或者如果您使用--noImplicitAny选项,则会为任何未知类型引发错误,需要添加类型注解。 61 | 62 | 这意味着TypeScript覆盖的代码量与您所写的类型相关。 写入类型时,类型覆盖将线性上升。 63 | 64 | ### 类型覆盖 65 | 在我们进一步之前,我应该解释一下什么是类型覆盖。![Uncovered code shown in red](https://cdn-images-1.medium.com/max/2000/1*CgIv2yvDU_GTscCRLFp6DA.png) 66 | 67 | 如果你观察代码中的值以及表达是并且询问类型检查“你知道这是什么类型吗?”。 68 | 69 | 70 | 71 | 如果类型检查知道这个类型,接着这个值或者表达式就被覆盖了。如果类型检查不知道这个类型,那么它就没有被覆盖。 72 | 73 | 类型检查器知道类型的代码的百分比是程序的“类型覆盖”。 74 | 75 | 你希望你的程序具有尽可能多的类型覆盖,因为那么他将能够告诉你在更多地方的错误。 76 | 77 | 如果没有类型覆盖,类型检查也就没什么意义了。 78 | 79 | ### 采用Flow 80 | ```javascript 81 | // @flow 82 | function square(n) { 83 | return n * n; 84 | } 85 | square("oops"); 86 | ``` 87 | 接着我们运行Flow会看到这个结果 88 | 89 | ```javascript 90 | function square(n) { 91 | return n * n; 92 | ^ ^ 93 | Error (x2) 94 | } 95 | square("oops"); 96 | Error (x2) 97 | string. The operand of an arithmetic operation must be a number. 98 | ``` 99 | 我们立刻就会得到类型错误,告诉我们某些地方有问题。 100 | 101 | Flow只需要我们输入文件以及外部模块的导出。其他的一切都可以被*推导出*。这使得代码覆盖快得多。只需要几种类型,你就可以获取具有非常高代码覆盖的文件。 102 | 103 | 以我自己的经历,我能够在几分钟内令文件的代码覆盖达到大约70-90%。 104 | 105 | 下面是一个超级科学的差异图: 106 | 107 | ![](https://cdn-images-1.medium.com/max/3728/1*mhy7hyBK_lQaHTsu6YB3uA.png) 108 | 109 | 这并不是我的个人观点,你可以自己去尝试一下,然后看下就利用几种类型会有什么不同。 110 | 111 | 为了在Flow中得到文件的代码覆盖,你可以运行: 112 | 113 | flow coverage path/to/file.js --color 114 | 你也可以利用[flow-coverage-report](https://github.com/rpl/flow-coverage-report) 来帮助你。 115 | 116 | > **注意:** 对于TypeScript我不知道任何代码覆盖报告工具(如果你知道的话,请给我发个链接!)但是你可已测试一下报告中错误的地方是否被代码覆盖检查所覆盖到。 117 | 118 | ## 它是如何工作的? 119 | 120 | 两种工具采用的不同行为的原因归根到底是因为其架构的区别 121 | 122 | ### TypeScript架构: AST-directed 123 | TypeScript将会遍历你的程序,并且构建已知类型的表。因为当它发现值以及表达式的化,会立刻给它分配一种类型。当TypeScript发现一个未知类型的时候,它必须立刻做出决定,这意味着要么将它分配到任何一种或者抛出一个错误。 124 | 125 | ### Flow架构: Graph-directed 126 | Flow会基于你的值和表达式以及它们之间的关系来构建一个图。它接着就会开始给每个值以及表达式分配类型。如果它发现一个未知类型,它会将它标志位一个“开放的”类型并且会在后面再处理。 127 | 128 | 一旦Flow获得你程序的完整图,它将会开始连接所有的点,*流动*类型将会从一个值传递到其它的。开放的类型接受其它值流动到它们的类型--生成的类型被成为推断类型。 129 | 130 | 你能够看到发生了什么.让我们看一下在世Flow之前的类型错误: 131 | 132 | ```javascript 133 | function square(n) { 134 | return n * n; 135 | ^ ^ 136 | Error (x2) 137 | } 138 | square("oops"); 139 | Error (x2) 140 | string. The operand of an arithmetic operation must be a number. 141 | ``` 142 | 注意到错误是指向n * n而不是square("oops")。因为我们没有为n指定一个类型,接着"opps"字符串就会流入到其中那么Flow就开始检查n是不是一个字符串。 143 | 144 | ```javascript 145 | function square(n: number) { 146 | return n * n; 147 | } 148 | square("oops"); 149 | ^ Error 150 | Error: string. 151 | This type is incompatible with the expected param type of number. 152 | ``` 153 | 这提出了重要的一点:因为Flow可以推导所有地方的类型,这并不意味着你不需要在你的代码中添加类型注解。 154 | 155 | ### 结论 156 | TypeScript和Flow都具有很好的过渡过程。逐个文件是一个很好的经历。然而,如果你使用Flow,你将会有更高的代码覆盖并且更快。这样你也能够睡得更安心。 157 | 158 | 使用Flow,您将添加类型以使错误更好展示,而不是发现它们。 159 | -------------------------------------------------------------------------------- /通过利用immutability的能力编写更安全和更整洁的代码.md: -------------------------------------------------------------------------------- 1 | # 通过利用immutability的能力编写更安全和更整洁的代码 2 | 3 | > 原文:[Write safer and cleaner code by leveraging the power of “Immutability”](https://medium.freecodecamp.com/write-safer-and-cleaner-code-by-leveraging-the-power-of-immutability-7862df04b7b6) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![](https://cloud.githubusercontent.com/assets/12164075/26274743/77a794ca-3d83-11e7-861f-6504b9c0e8c6.png) 12 | 13 | Immutability是函数式编程的重要基础之一。它允许你能编写更安全以及更整洁的代码。我将会通过一些JavaScript例子来向你展示如何来达到immutability。 14 | 15 | **根据维基百科:** 16 | 17 | >不可变对象是一个在创建之后不能修改其状态的对象。这正与可变对象相反,它能够在创建之后被修改。在某些情况下,对象被认为是不可变的,即使其内部的某些属性发生改变,但是从外部的角度来看这个对象的状态看起来还是没有发生变化的。 18 | 19 | ## Immutable数组 20 | 21 | 数组是理解immutability如何工作的很好的起点。让我们一起来看一看。 22 | 23 | ```javascript 24 | const arrayA = [1, 2, 3]; 25 | arrayA.push(4); 26 | 27 | const arrayB = arrayA; 28 | arrayB.push(5); 29 | 30 | console.log(arrayA); // [1, 2, 3, 4, 5] 31 | console.log(arrayB); // [1, 2, 3, 4, 5] 32 | ``` 33 | 34 | 这个例子将**arrayA**的引用分配给**arrayB**,因此这个push方法在这两个变量中都会添加5这个值。我们的代码间接地修改其它的值,这并不是我们想要的。这也违反了immutability的原则。 35 | 36 | 我们可以通过使用 [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice)函数将我们的例子提升为immutable,并且这个代码的行为也产生了变化。 37 | 38 | ```javascript 39 | const arrayA = [1, 2, 3]; 40 | arrayA.push(4); 41 | 42 | const arrayB = arrayA.slice(0); 43 | arrayB.push(5); 44 | 45 | console.log(arrayA); // [1, 2, 3, 4] 46 | console.log(arrayB); // [1, 2, 3, 4, 5] 47 | ``` 48 | 49 | 这正是我们想要的。代码没有改变其它值。 50 | 51 | 提醒:当你使用 [push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) 向数组添加一个值的时候,你是在**改变**这个数组。你想要避免修改变量,因为这可能会给你的代码带来负面影响。 [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice)函数能够返回数组的拷贝。 52 | 53 | ## 函数 54 | 55 | 现在你知道如何避免修改其它值。那么你知道如何写“纯”函数了嘛?纯函数是对于一个不会又任何副作用以及不会改变状态的函数另一个称呼。 56 | 57 | 我们来看一个利用数组示例中相同原理的函数。 首先,我们创建一个改变其它值的函数,然后我们将该函数改进为“纯”。 58 | 59 | ```javascript 60 | const add = (arrayInput, value) => { 61 | arrayInput.push(value); 62 | 63 | return arrayInput; 64 | }; 65 | const array = [1, 2, 3]; 66 | 67 | console.log(add(array, 4)); // [1, 2, 3, 4] 68 | console.log(add(array, 5)); // [1, 2, 3, 4, 5] 69 | ``` 70 | 71 | 因此再一次,我们**修改**我们的输入,这会产生一个无法预测的函数。在函数式编程的世界中,对于函数有一个黄金法则:**使用相同输入的函数应该返回相同的结果。** 72 | 73 | 上述的函数违反了这一黄金法则。每一次我们的**add**函数被调用的时候,它就会修改这个**array**变量,结果也就不同了。 74 | 75 | 让我们一起看看看如何改变我们**add**函数的事先,因此让其成为immutable。 76 | 77 | ```javascript 78 | const add = (arrayInput, value) => { 79 | const copiedArray = arrayInput.slice(0); 80 | copiedArray.push(value); 81 | 82 | return copiedArray; 83 | }; 84 | 85 | const array = [1, 2, 3]; 86 | const resultA = add(array, 4); 87 | console.log(resultA); // [1, 2, 3, 4] 88 | const resultB = add(array, 5); 89 | console.log(resultB); // [1, 2, 3, 5] 90 | ``` 91 | 92 | 现在我们可以调用我们的函数多次,并且可以预期在相同输入的时候,输出都是相同的。这是因为我们不再会修改这个**array**变量。我们能够将这个函数成为“纯函数”。 93 | 94 | > **注意**:你也能使用**concat**,而不是**slice**以及**push**。 95 | > 96 | > 因此:arrayInput.concat(value) 97 | 98 | 我们能够利用ES6中的[扩展语法]((https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Operators/Spread_operator)来缩短函数。 99 | 100 | ``` 101 | const add = (arrayInput, value) => […arrayInput, value]; 102 | ``` 103 | 104 | ### 并发 105 | 106 | NodeJS应用使用了一个叫做并发的概念。一个并发操作意味着两个计算能够能够同时进行并且不用考虑另外一个。如果这里有两个线程的话,第二个计算不需要等到第一个计算完成才能只需执行。 107 | 108 | ![](https://cloud.githubusercontent.com/assets/12164075/26275010/948ad254-3d89-11e7-8a1a-300144626274.png) 109 | 110 | NodeJS通过event-loop让并发变得可能。event-loop会重复获取一个事件,并且每次会激活任一一个事件处理器来监听事件。这个模型允许NodeJS应用处理大量的请求。如果你想了解更多,阅读[这篇关于event-loop的文章](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick)。 111 | 112 | Immutability和并发之间有什么关系呢?因为做个操作能够在函数的作用域外以并发的方式改变值,这会产生一个不可靠的输出以及无法预期的结果。意识到函数可能会在作用域外修改变量,因此这可能会非常危险的。 113 | 114 | ### 下一步 115 | 116 | Immutability对于你理解和学习函数式编程是非常重要的一个概念。你可能希望了解mmutableJS](https://facebook.github.io/immutable-js),其由Facebook开发者编写。这个library提供了某些不可变的数据机构,比如 **Map**, **Set**以及**List**. 117 | 118 | [Immutable.js, persistent data structures and structural sharing](https://medium.com/@dtinth/immutable-js-persistent-data-structures-and-structural-sharing-6d163fbd73d2)(译者注:墙外地址) -------------------------------------------------------------------------------- /gitlab-bug-boungty-2022.md: -------------------------------------------------------------------------------- 1 | # 为什么 2022 年是漏洞赏金奖破纪录的一年 2 | 3 | >原文:[Why 2022 was a record-breaking year in bug bounty awards](https://about.gitlab.com/blog/2022/12/19/why-2022-was-a-record-breaking-year-in-bug-bounty-awards/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![](/images/blogimages/inside-gitLab-public-bug-bounty-program.png) 12 | 13 | 每年,GitLab 的[应用安全团队](https://about.gitlab.com/handbook/security/security-engineering/application-security/) 都会回顾 GitLab 漏洞赏金计划的亮点。 14 | 15 | 对于整个行业的安全团队来说,2022 年是忙碌的一年,我们很幸运收到了大量出色的报告,帮助我们确保 GitLab 及其客户的安全。 随着我们在 2021 年 11 月 [增加我们的漏洞赏金奖励金额](https://about.gitlab.com/blog/2021/11/01/3rd-annual-bug-bounty-contest/#-increased-bounties-across-all-bounty-ranges-)和研究人员参与度的提高,我们在 2022 年期间**奖励超过 100 万美元**,打破了新纪录! 16 | 17 | 如果没有我们的漏洞赏金社区的合作,我们就不会取得今天的成就,我们认为这些奖励非常有益,而且钱花得值。 18 | 19 | 2022 年的数字[](##2022-by-the-numbers) 20 | ------------------------------------------ 21 | 22 | * 在 221 份有效报告中获得总计 1,055,770 美元的奖金,高于去年的 337,780 美元! 23 | * 三名研究人员在他们的多份报告中获得了 10 万美元以上的收入,另外七名研究人员的收入超过了 2 万美元。 24 | * 2022年共收到424名研究人员的920份报告。 25 | * 解决了 158 份有效报告并公开了 94 份 - 今年,我们收到了一些信息泄漏报告,与漏洞不同,这些报告不需要公开 GitLab 问题。 26 | * 今年有 138 名安全研究人员提交了一份以上的报告,表明他们对我们的计划做出了积极的贡献。 27 | * 向提交三份或更多有效报告的研究人员授予八份 GitLab Ultimate 许可证。 28 | 29 | _注:数据为截至 2022 年 12 月 16 日。_ 30 | 31 | 您可以在我们的 [HackerOne 项目主页](https://hackerone.com/gitlab) 上查看每天更新的项目统计信息。如果您想参与其中,这也是开始我们计划的地方! 32 | 33 | 脱颖而出的报告和上报者[](##reports-and-reporters-that-stand-out) 34 | ---------------------------------------------- -------------------------- 35 | 36 | **我们计划的最有效报告**。祝贺 [@joaxcar](https://hackerone.com/joaxcar) 在 2022 年提交了 22 份有效且现已解决的报告。 37 | 38 | **来自我们计划新人的最有效报告**, 欢迎并祝贺 [@albatraoz](https://hackerone.com/albatraoz) 在 2022 年提出了七份有效且现已解决的报告。 39 | 40 | **最佳书面报告**。干得好,谢谢 [@yvvdwf](https://hackerone.com/yvvdwf) 编写了一个非常有趣的 [远程代码执行错误](https://gitlab.com/gitlab-org/gitlab/-/issues/371098?_gl=1*w2k5zo*_ga*MTE4NzUwNTYwNC4xNjcyODE5MjA1*_ga_ENFH3X7M5Y*MTY3MzgyOTM5OS4zLjEuMTY3MzgyOTkzOC4wLjAuMA..)。代码和根本原因的 walkthrough、创建虚拟恶意服务器的脚本,以及在验证期间与我们的 AppSec 团队的协作非常棒! 41 | 42 | **最具创新性的报告**。击掌,[@vakzz](https://hackerone.com/vakzz),他用[新颖的本地 `git` 读取漏洞](https://gitlab.com/gitlab-org/gitlab/-/issues/372165)夺得了旗帜! 他还对上述 `@yvvdwf` 的 RCE 进行了[简洁的跟进](https://gitlab.com/gitlab-org/gitlab/-/issues/371884)。 43 | 44 | **最具影响力的发现**。我们很高兴认识到 [@taraszelyk](https://hackerone.com/taraszelyk),他连续提交的信息披露导致 GitLab 内部发生了许多积极的安全变化。谢谢,Taras! 45 | 46 | 我们将与这些研究人员取得联系,寄出 [GitLab Swag Shop](https://shop.gitlab.com) 代金券以示感谢。 47 | 48 | 2022 年所做的更改[](##changes-made-in-2022) 49 | ------------------------------------------ 50 | 51 | * 我们采用了 HackerOne 的黄金标准安全港声明。请参阅 [来自 HackerOne 的公告](https://www.hackerone.com/press-release/hackerone-announces-gold-standard-safe-harbor-improve-protections-good-faith-security)。 52 | * 我们推出了 [20,000 美元的夺旗奖金](https://hackerone.com/gitlab#user-content-capture-the-flag-for-20000),[已经被获得了一次](https://gitlab.com/gitlab-org/gitlab/-/issues/372165)。 53 | * 我们创建了 [HackerOne Questions](https://gitlab.com/gitlab-com/gl-security/appsec/hackerone-questions/),这是一个专门用于在 HackerOne 报告之外与 AppSec 团队联系的空间。 54 | * 创建了 ["Reproducible Vulnerabilities"](/handbook/security/security-engineering-and-research/application-security/reproducible-vulnerabilities.html),这是我们手册中的全新学习资源,具有可扩展的提示部分,以便您可以挑战自己并学习如何找到真正的安全漏洞。 55 | * 继续透明地迭代我们的 [HackerOne 分类流程](https://gitlab.com/gitlab-com/www-gitlab-com/-/commits/master/sites/handbook/source/handbook/security/security-engineering-and-research/application-security/runbooks/hackerone-process.html.md?_gl=1*q768y9*_ga*MTE4NzUwNTYwNC4xNjcyODE5MjA1*_ga_ENFH3X7M5Y*MTY3MzgyOTM5OS4zLjEuMTY3MzgyOTkzOC4wLjAuMA..),以及我们的 [漏洞赏金计算器](https://gitlab.com/gitlab-com/gl-security/appsec/cvss-calculator/-/commits/master),包括标准化非漏洞报告的数量,如信息泄漏。 56 | 57 | 今年,我们还继续提供有助于研究人员和其他运行漏洞赏金计划的组织的内容: 58 | 59 | * GitLab 博客:[“想开始黑客攻击吗?这是快速深入的方法”](https://about.gitlab.com//blog/2022/07/27/cracking-our-bug-bounty-top-10/) 60 | * GitLab 博客:[“GitLab 如何处理安全漏洞(及其重要性)”](https://about.gitlab.com//blog/2022/02/17/how-gitlab-handles-security-bugs/) 61 | * YouTube:[NullCon 2022 视频座谈会:“CXO 座谈会:漏洞赏金?太棒了!现在怎么办?”](https://www.youtube.com/watch?v=uqvaiml1iV4) 62 | 63 | 一如既往,与我们行业最好的安全研究人员(包括许多新人)一起工作真的很高兴。 GitLab 的 AppSec 团队致力于在漏洞赏金计划和奖励的透明度方面成为行业领导者。 [让我们知道我们在做什么](https://gitlab.com/gitlab-com/gl-security/appsec/hackerone-questions/) 这样我们就可以迭代我们的程序流程。 64 | 65 | 为 2023 年干杯 - 快乐挖洞! 66 | 67 | -------------------------------------------------------------------------------- /什么是服务端伪造(SSRF)?.md: -------------------------------------------------------------------------------- 1 | # 什么是服务端伪造(SSRF)? 2 | 3 | > 原文:[What is Server Side Request Forgery (SSRF)?](https://www.acunetix.com/blog/articles/server-side-request-forgery-vulnerability/) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 服务端伪造(SSRF)指的是攻击者从一个具有漏洞的web应用中发送的一个伪造的请求的攻击。SSRF通常适用于针对在防火墙后一般对于外部网络的攻击者是无法访问的内部系统。另外,攻击者也可能利用SSRF来访问监听回送地址接口(127.0.0.1)的服务。 12 | 13 | 典型的SSRF发生在web应用发送请求的时候,攻击者对这个发送的请求具有全部或者部分的控制。一个通用的例子就是攻击者能够控制全部或者部分web应用向第三方服务发送请求的URL。 14 | 15 | ![SSRF](https://user-images.githubusercontent.com/12164075/28745292-2d209ce2-74a8-11e7-9858-214153c97aa2.png) 16 | 17 | 下面的是PHP中容易收到SSRF的一个例子。 18 | 19 | ```php 20 | 原文:["steganography" - obfuscating PDF exploits in depth](https://blog.edgespot.io/2019/01/steganography-obfuscating-exploits.html) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | [上礼拜发现的](https://blog.edgespot.io/2019/01/an-interesting-obfuscation-method.html)关于使用 `this.getPageNumWords() & this.getPageNthWord()` 方法来进行混淆的 PDF 漏洞不久,我们发现另外一个,一个在 PDF 漏洞中更加强大的混淆利用技术。这种技术使用所谓的“隐写术”方法来隐藏嵌入在 PDF 文件中的图像中的恶意 Javascript 代码,它非常强大,因为它可以绕过几乎所有的 AV 引擎。 12 | 13 | 我们的 EdgeLogic 引擎将样本检测为 "exploit CVE-2013-3346",与前一个相同。 14 | 15 | * https://edgespot.io/analysis/ebc5617447c58c88d52be6218384158ccf96ec7d7755179a31d209a95cd81a69/ 16 | 17 | ![](https://4.bp.blogspot.com/-Kr-NkDqfyho/XEdDnFNT1EI/AAAAAAAAAEo/d9VFG0l_qDwAB_vhf50p7AHCZjNncLPuQCLcBGAs/s1600/edgespot-detection.png) 18 | 19 | 样本首先在 2017-10-10 提交给 VirusTotal,文件名为 “oral-b oxyjet spec.pdf”。 20 | 21 | ![](https://lh4.googleusercontent.com/ORMvSEL5-R-yLYe8ow9YzjUkUWBfXSTxa8d55dxZhoot91KnVhLvyvjd0nBUbPJk9sH433KsJDgdSZnu52NWm-9mbf5uPQv-gMGalUX918rX7HSAJyFj3OQq1zpNsUqrKVlc_Qrf) 22 | 23 | 上周只有 1 个 AV 引擎检测到这种攻击(但是,截至写作时,检测增加到 5/57)。 24 | * https://www.virustotal.com/#/file/ebc5617447c58c88d52be6218384158ccf96ec7d7755179a31d209a95cd81a69/detection 25 | 26 | ![](https://3.bp.blogspot.com/-O2dvXaoaRIw/XEdTFYN-N3I/AAAAAAAAAGI/wdCOW241LCQxQgP99qbzggvgoSMLmVRSwCEwYBhgL/s1600/24.png) 27 | 28 | 打开后,伪装成 IRS 文件的 PDF 看起来很正常。 29 | 30 | ![](https://4.bp.blogspot.com/-_zJ5pKPgv3I/XEdH34_gUOI/AAAAAAAAAE4/KYsV8Wi3phs4FWS3xJ8yZnI9jZXnNgAhwCLcBGAs/s1600/16.png) 31 | 32 | 在该样本中使用两层混淆。 第一层是我们之前公开的 - "this.getPageNumWords()" 以及 "this.getPageNthWord()" 方法。该漏洞使用 "this.getPageNumWords()" 以及 "this.getPageNthWord()" 来读取和执行隐藏为“内容”的 Javascript。 相关代码可以在 PDF stream-64中找到。 33 | 34 | ![](https://lh6.googleusercontent.com/Qa4otHEzSjZlj4B65CmnfgutxzaTfn4EugYFlSf0BaMQdyntnVpxr7qzgwjAdzY3Ue97axGjscZtt2dumd7bKlutVi1aDi9ElBSPm17xJkgmIPM902ailGHvnOGRjtfpy_ADT_-_) 35 |

stream-64

36 | 37 | 第二层是新的,这是我们本文的重点。 “Javascript 内容”存储在 stream-119 中,让我们看看它什么样。 38 | 39 | ![](https://lh6.googleusercontent.com/daXGdDM5pyT4_kjmoaPsX9jnXZRbq9fIF22cHznr97dqymfQ8TLJ1KpnsK7LswND3Tfo-cVqXG_VyxOD_amxM2Pi_bpUFUzG1xLPJLq_-EIzLDWS4PBHGZzcb4Aw0aXZEpipBv0X) 40 | 41 | 美化 Javascript 后,显示如下: 42 | 43 | ![](https://1.bp.blogspot.com/-ux7d0FWJFqM/XEdNBe3NpMI/AAAAAAAAAFE/JaVx-Zq4P0kRFc7E9C1RRkGya_6hFrrkwCLcBGAs/s1600/22.png) 44 | 45 | 为了弄清楚 Javascript 做了什么,我们首先需要学习这两个 PDF JS API,`this.getIcon()` 和 `util.iconStreamFromIcon()`。 以下是 Adobe 参考文献的摘录。 46 | 47 | ![](https://2.bp.blogspot.com/-n78eqA8dplg/XEdNwvK8GCI/AAAAAAAAAFM/l4fI0jyNbbUZilcpU2zsNfyHL5holqNgQCLcBGAs/s1600/4.png) 48 | 49 | 50 | 51 | ![](https://2.bp.blogspot.com/-2-4DtAFE_2c/XEdN0UrwVrI/AAAAAAAAAFc/3q4W0pMMGkwmnhuyXBe-8yCkqUAvWEwYQCLcBGAs/s1600/5.png) 52 | 53 | 根据 API 参考资料,这两个 API 协同工作,用于读取存储在 PDF 文件中的名为 “icon” 的图像流。 54 | 55 | 通过检查上面的 Javascript 代码,我们发现代码的功能是读取和解码隐藏在图标流中的“消息”。 一旦成功读取“消息”,它将通过 “eval(msg)” 执行“消息”作为 Javascript 代码。 56 | 57 | object-131 中名为 “icon” 的图标流可以保存为 “jpg” 文件,并在图像查看器中查看,没有问题。 如下所示: 58 | 59 |

60 | 61 |

当图像仍然可见时,恶意数据隐藏在图像中

62 |

63 | 64 | 然而,图标文件中没有可疑数据,因为恶意代码数据被严重混淆。 65 | 66 | 最终执行的 Javascript 是什么样的?在成功去混淆之后,这是一段真实的代码。 67 | 68 | ![](https://lh4.googleusercontent.com/Iun-DdCJrtuagzxaB1eYLCX5_Ecu0MCTTV-P3cBxUGlxJKdVSIqFsnCTZFMym2HzpUIvKqpoEDK8gEt6WMmfxWBdgJCqHIRgTC25dDjKOMoxcCstabRGkRsIWMq9BNb6xzd0VqNR) 69 | 70 | 因此,我们确认这个漏洞利用为 CVE-2013-3346。 71 | 72 | 此外,我们推断该样本和[前一个](https://edgespot.io/analysis/6e71c6ff75abf5b7f40a2b1ed7480757af2f4af191797f19d1b4a46e8ecfa448/)来自同一作者,原因如下。 73 | 他们都利用相同的漏洞 (CVE-2013-3346)。这两个漏洞利用中 Javascript 代码的相似性。 74 | 经过一些谷歌搜索,我们发现攻击者可能复制了一个名为 “steganography.js” 的项目/技术,开源在[这里](https://www.peter-eigenschink.at/projects/steganographyjs)。该项目是在浏览器上开发的。 我们相信 PDF 样本背后的人在成功利用 PDF 格式的技术时进行了创新。我们之前在 PDF 漏洞中找不到任何提及此类技术的信息,因此我们相信这是第一次使用“隐写术”技术隐藏 PDF 漏洞。 75 | 76 | ### 总结 77 | 78 | 我们对这种技术印象深刻,这种技术非常适合 PDF 漏洞的恶意代码混淆。通过使用这种技术所有流看起来都很正常,所有图像都是可见的,一切看起来都合法。这可以解释为什么几乎所有 AV 引擎都没有识别它。 79 | 80 | 在这篇博客中,我们研究了用于混淆 PDF 漏洞的真正先进的“隐写术”技术,这是我们的 EdgeLogic 引擎的强大功能,因为我们能够击败这种混淆技术,以及其他许多技术。 81 | 82 | 就像前一个一样,“隐写术”技术不仅可以用于混淆这种利用(CVE-2013-3346),而且还可以应用于许多其他PDF 漏洞,包括零天。我们要求安全维护者密切关注它。 83 | 84 | 通过 @EdgeSpot_io 追随我们。 85 | -------------------------------------------------------------------------------- /对Pornhub的Web开发者的采访.md: -------------------------------------------------------------------------------- 1 | # Pornhub Web 开发者访谈 2 | 3 | >原文:[Interview with a Pornhub Web Developer](https://davidwalsh.name/pornhub-interview) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 无论你对色情内容采取何种立场,都无法否认成人网站行业对推动互联网发展具有巨大影响。从将浏览器的视频限制推送到[通过WebSocket推送广告](https://medium.com/thebugreport/pornhub-bypasses-ad-blockers-with-websockets-cedab35a8323),以便广告拦截器无法检测到它们,你必须足够聪明才能在互联网的前沿进行创新。 12 | 13 | 最近,我很有幸采访互联网最大的成人网站 Pornhub 的一名 Web 开发者。我想了解技术,Web API 如何改进以及在成人网站上工作的感受。请享用! 14 | 15 | *注意:成人产业竞争激烈,因此有一些他们无法回答的问题。我尊重他们保守商业机密的需要。* 16 | 17 | **成人网站显然会显示许多图形内容。在开发过程中,你是否使用了大量的占位符图像和视频?最终产品和开发时的内容和经验有什么区别?** 18 | 19 | 实际上,我们在开发网站时不使用占位符!其次,重要的是代码和功能,接口是我们现在非常习惯的东西。一开始肯定会有一些学习曲线,但是我们大家很快就习惯了。 20 | 21 | **对于网络流和第三方广告脚本,你如何在网站和功能开发过程中模拟这些重要的动态资源?** 22 | 23 | 为了进行开发,播放器分为两个部分。基本播放器实现核心功能并触发事件。开发不会受其他因素干扰。为了在网站上进行集成,我们希望运行那些第三方脚本和广告,以便我们尽早发现问题。在特殊情况下,我们将与广告客户合作,允许我们手动触发通常可能是随机的事件。 24 | 25 | **平均每个页面可能至少包含一个视频,GIF 广告,一些 cam 表演者预览以及其他视频的缩略图。你如何测量页面性能以及如何使页面保持最佳性能?有什么你可已分享的技巧吗?** 26 | 27 | 我们使用一些测量系统。 28 | 29 | * 我们的播放器会向我们报告有关视频播放性能和一般用法的指标 30 | * 用于一般站点性能的第三方 RUM 系统。 31 | * WebpageTest 私有实例,用于在可用的 AWS 数据中心中编写测试脚本。我们主要将其用于查看给定时间可能发生的情况。它还使我们能够查看来自不同位置和提供者的“瀑布”。 32 | 33 | **我必须假设前端最重要,最复杂的功能是视频播放器。从在视频之前加入广告,标记视频的精彩时刻,更改视频速度和其他功能,你如何维护该资产的性能,功能和稳定性?** 34 | 35 | 我们有一支专门致力于视频播放器的团队,他们的首要任务是持续监控性能和效率。我们为此几乎使用了所有可用的东西;浏览器性能工具,网页测试,指标等。我们进行的所有更新均通过可靠的质量检查来确保稳定性和质量。 36 | 37 | **专门的视频团队有多少人?团队中有多少前端开发人员?** 38 | 39 | 我要说的是,团队规模倾向于基于产品规模的平均水平。 40 | 41 | **在成人网站上工作期间,你如何看待前端未来的变化?哪些新的 Web API 使你的生活更轻松?** 42 | 43 | 我肯定在前端世界的每个方面都看到了很多改进; 44 | 45 | * 从纯 CSS 到最终使用 LESS 和 Mixins,再到使用具有媒体查询和图片标签的灵活 Grid 系统,以适应不同的分辨率和屏幕尺寸 46 | * jQuery 和 jQueryUI 慢慢地被淘汰,因此我们将回到 vanilla JS 中更高效的面向对象编程。在某些情况下,框架也非常有趣 47 | * 我们喜欢新的 IntersectionObserver API,对于以更有效的方式加载图像非常有用 48 | * 我们也开始使用画中画 API,以便在我们的某些页面上播放该浮动视频,主要是为了获得用户对该想法的反馈。 49 | 50 | **展望未来,有没有你想要更改,改进甚至创建的 Web API?** 51 | 52 | 53 | 其中有一些是我们希望改变或改进的;Beacon,WebRTC, Service Workers 以及 Fetch: 54 | 55 | * Beacon:在 IOS 上存在 pageHide 事件无正常工作的问题 56 | * Fetch:没有下载进度,也没有提供拦截请求的方法 57 | * WebRTC:如果分辨率不够大,则即使进行屏幕共享,Simulcast 层也会受到限制 58 | * Service Workers:调用 navigator.serviceWorker.register 不会被任何 Service Workers 的 Fetch 事件处理程序拦截 59 | 60 | **WebVR 在过去几年中一直在进步--WebVR 在当前状态下作用有多大,成人网站为支持 VR 内容付出了多少努力?触觉在你们网站上的 WebVR 中有起到作用吗?** 61 | 62 | 我们正在研究 webXR 以及如何最好地适应新兴的空间计算用例,作为最大的发布平台,我们需要支持创作者和用户,无论他们想体验我们的内容如何。但是,我们仍在探索这些新媒体应具有什么样的内容和平台。 63 | 64 | 我们是第一个支持 VR,计算机视觉和虚拟表演者的主要平台,并将继续推动新技术和开放互联网的发展。 65 | 66 | **每个页面上的媒体和内容种类繁多,那么桌面设备与移动设备之间最大的考虑是什么?** 67 | 68 | 功能主要受操作系统和浏览器类型的限制。当涉及一组套完全不同的访问和功能时,iOS 对比 Android 是一个完美的例子。 69 | 70 | 例如,某些 iOS 移动设备不允许我们在全屏模式下使用自定义视频播放器,而是强制使用本机 QuickTime 播放器。我们提出新想法时必须考虑这一点。另一方面,Android 为我们提供了完全的控制权,我们可以将功能在全屏模式实现。 71 | 72 | HLS 中的自适应流式传输也是另一个示例,当涉及到 HLS 流式传输质量时,IE 和 Edge 需要有所顾虑,因为我们需要防止某些更高质量的内容,否则视频将不断卡顿并出现伪像。 73 | 74 | **当前针对你工作的成人网站的最低浏览器版本支持是什么? IE 浏览器上是否已淘汰?** 75 | 76 | 我们对 IE 的支持时间很长,但是最近放弃了对 IE11 之前的任何版本的支持。有了它,我们也停止了为视频播放器使用 Flash。我们主要关注 Chrome,Firefox 和 Safari。 77 | 78 | **更广泛地说,你能否分享一些有关典型成人网站技术栈的信息?服务器和/或前端?你正在使用哪些库?** 79 | 80 | 我们的大多数网站都以以下内容为基础: 81 | 82 | * Nginx 83 | * PHP 84 | * MySQL 85 | * Memcached 和/或 Redis 86 | 87 | 在适当的地方使用其他技术,例如 Varnish,ElasticSearch,NodeJS,Go,Vertica。 88 | 89 | 对于前端,我们主要运行原生 Javascript,我们逐渐摆脱了 jQuery,我们才刚刚开始使用框架,主要是Vue.js 90 | 91 | **从局外人的角度来看,成人网站通常看起来很相似:很多视频缩略图,聚合的视频内容,摄像头表演,广告。作为从事这些工作的人,使成人网站与众不同的特征是什么?** 92 | 93 | 我们非常努力地为每个品牌赋予不同层次的独特性;内容库,UX 和功能集,以及许多不同的算法。 94 | 95 | **在你申请这份工作和面试之前,你对在成人场所工作的想法是什么?你有犹豫吗?如果是这样,你如何释怀的?** 96 | 97 | 这真的从来没有困扰过我,最终挑战是如此吸引人。数以百万计的人会使用我正在开发的功能确实令人鼓舞。事实证明,这很快就成立了,我第一次的工作成果上线了,我感到非常自豪,我的确告诉所有朋友去看看!色情片永远不会消失的事实也使工作稳定得到了保证! 98 | 99 | **就最终产品而言,分享下你在成人网站上工作可能与在本地互联网公司上工作不同。你会羞于告诉朋友,家人和熟人在成人网站工作吗?你是否会犹豫告诉别人你在成人网站工作?** 100 | 101 | 我为能够为这些产品工作而感到自豪,与我亲近的人都知道并着迷于这些产品。它始终是交谈,笑话的绝佳来源,而且非常有趣。 102 | 103 | **曾在成人产业以外的机构工作过,和在成人网站工作时气氛有差异吗?** 104 | 105 | 这里的气氛非常轻松友好。除了在这里比我以前工作过的任何地方都大得多的事实外,我没有注意到和其他机构在工作文化方面的任何重大差异。 106 | 107 | 作为前端开发人员,你与哪些团队合作最紧密?最常见的日常交流方式是什么? 108 | 109 | 我们与后端开发人员,QA 测试人员和产品经理平等地合作--大多数时候,我们只是在彼此的办公桌旁交谈。另外使用 cat(MS Teams)非常普遍。然后就是电子邮件。 110 | 111 | 112 | **最后,作为在成人网站上工作的前端开发人员,你有什么想分享的吗?** 113 | 114 | 作为创造用户如何体验如此广泛使用的产品的一部分,确实令人兴奋。随着技术的不断发展,我们通常处于趋势和技术重大变革的最前沿,这使它保持乐趣和挑战性。 115 | 116 | *访谈结束* 117 | 118 | 我发现我们的采访确实很有启发性。我很惊讶他们在开发功能和设计时没有使用图像。很高兴看到 Pornhub 继续使用 WebXR,WebRTC 和 Intersection Observer 推动互联网的前沿发展。我也很高兴看到他们认为当前的 Web API足够了从而开始移除 jQuery。 119 | 120 | 我真的希望我能够从中获得更多具体的技术提示;性能和巧妙的技巧。我敢肯定,他们的源代码背后有很多知识要学习!你会问什么问题? 121 | -------------------------------------------------------------------------------- /理解跨域资源共享.md: -------------------------------------------------------------------------------- 1 | # 理解跨域资源共享 2 | 3 | >原文:[Understanding CORS](https://akshaysin.github.io/cors.html) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | CORS 或跨源资源共享是一种 http 机制,它允许用户通过使用一些额外的头来访问别的域的资源。 例如,假设位于[http://test1.domain.com](http://test1.domain.com/)上的应用程序需要对位于 [http://test2.domain.com/some/awesome/endpoint](http://test2.domain.com/some/awesome/endpoint)上的 api 进行 REST 调用。 12 | 13 | 现在默认情况下,浏览器不允许这样的请求。这是出于 http 安全原因考虑。这意味着浏览器不允许从网页上的脚本中发出的请求访问位于除最初加载的网站之外的域上的任何 HTTP 资源。例如,XMLHttpRequest 和Fetch API 都遵循同源策略。这就是 CORS 的用武之地。CORS 通过首先使用一些特殊的头来验证[test2.domain.com](http://test2.domain.com/)来实现。 14 | 15 | ![CORS](https://cdn-images-1.medium.com/max/2000/1*jGd3qoZ-eMvejkXNOiSHBA.png) 16 | 17 | ## 头 18 | 19 | 和 CORS 相关的头包括 20 | 21 | **请求头** 22 | 23 | * Origin 24 | 25 | * Access-Control-Request-Method 26 | 27 | * Access-Control-Request-Headers 28 | 29 | **响应头** 30 | 31 | * Access-Control-Allow-Origin 32 | 33 | * Access-Control-Allow-Credentials 34 | 35 | * Access-Control-Expose-Headers 36 | 37 | * Access-Control-Max-Age 38 | 39 | * Access-Control-Allow-Methods 40 | 41 | * Access-Control-Allow-Headers 42 | 43 | ## 功能概述 44 | 45 | CORS 工作的方式是: 46 | 47 | 1. 浏览器遇到一个发送给 [test2.domain.com](http://test2.domain.com/) 的请求。 48 | 49 | 2. 它会检查这个请求是否是 GET 或者 HEAD,如果是的话,它将会查找任意自定义 HTTP 头。如果发现任意一个,它将会转到步骤3,否则它会继续处理真实请求,比如步骤 7. 50 | 51 | 3. 浏览器将会使用 *Origin*, *Access-Control-Request-Method * 以及 *Access-Control-Request* 头向 [test2.domain.com](http://test2.domain.com/) 发送一个 OPTIONS 请求。 52 | 53 | 4. [test2.domain.com](http://test2.domain.com/) 必须现在响应合适的 *Access-Control-* 头。 54 | 55 | 5. 如果在 OPTIONS 请求的响应头中没有发现合适的 *Access-Control-* 头的话就会错误终止。 56 | 57 | 6. 如果在 OPTIONS 请求的响应头中发现合适的 *Access-Control-* 头的话就会继续步骤 7。 58 | 59 | 7. 发送真正的请求。 60 | 61 | ## 实现 62 | 63 | 现在,如果[test2.domain.com](http://test2.domain.com/)是一个 api 网关,我们可以通过在网关设置中启用 CORS 选项使其与 CORS 兼容。但是,如果你发现自己处于域甚至网关不支持此功能的情况下,请不要担心,仍有一种方法。 64 | 65 | 你可以在 F5 通过创建 iRule 来插入这些自定义头让[test2.domain.com](http://test2.domain.com/) CORS 兼容。 66 | 67 | ``` 68 | 69 | when HTTP_REQUEST priority 200 { 70 | unset -nocomplain cors_origin 71 | if { ( [HTTP::header Origin] contains "test1.domain.com" ) } { 72 | if { ( [HTTP::method] equals "OPTIONS" ) and ( [HTTP::header exists "Access-Control-Request-Method"] ) } { 73 | # CORS preflight request - return response immediately 74 | HTTP::respond 200 "Access-Control-Allow-Origin" [HTTP::header "Origin"] \ 75 | "Access-Control-Allow-Methods" "POST, GET, OPTIONS" \ 76 | "Access-Control-Allow-Headers" [HTTP::header "Access-Control-Request-Headers"] \ 77 | "Access-Control-Max-Age" "86400" \ 78 | "Access-Control-Allow-Credentials" "true" 79 | } else { 80 | # CORS GET/POST requests - set cors_origin variable 81 | set cors_origin [HTTP::header "Origin"] 82 | log local0. "Requested hostname: [HTTP::host] from IP: [IP::local_addr]" 83 | } 84 | } 85 | } 86 | when HTTP_RESPONSE { 87 | # CORS GET/POST response - check cors_origin variable set in request 88 | if { [info exists cors_origin] } { 89 | HTTP::header remove Access-Control-Allow-Origin 90 | HTTP::header remove Access-Control-Allow-Credentials 91 | HTTP::header remove Vary 92 | HTTP::header insert "Access-Control-Allow-Origin" $cors_origin 93 | HTTP::header insert "Access-Control-Allow-Credentials" "true" 94 | HTTP::header insert "Vary" "Origin" 95 | } 96 | 97 | ``` 98 | 99 | 这样就可以了. 100 | 101 | ## 特殊的例子 102 | 103 | 我在使用 CORS 时发现了一个非常有趣的案例,我认为这可能值得一提。设置是这样的,我有一个在 domain_a 托管的网站。它需要在 domain_b 上托管的资源。现在 domain_b 是一个 API 网关,我在网关上启用了开箱即用的 CORS 功能,并认为这样就可以了。我发现除了一个对网关后面的 websphere 服务器上托管的应用程序的资源特殊调用之外,所有对网关的调用都是通过的,这个调用是在。该调用总是错误地出现相同的之前的 CORS 错误: 104 | 105 | ``` 106 | No 'Access-Control-Allow-Origin' header is present on the request resource. Origin '[http://test1.domain.com](http://test1.domain.com/)' is therefore not allowed access. 107 | ``` 108 | 109 | 仔细观察,可以发现响应头中已经丢失了 Access-Control-* 。 现在,Websphere 带有自己的 http 服务器,结果证明 http 服务器占用了访问控制头。基于此可以很容易地通过修改 websphere上的 http.conf 来修复。 110 | 111 | 因此,如果你遇到类似这样的问题,请始终确保验证你的基础架构中是否有任何基础 http/Web服务器。 112 | 113 | 我是 Devops 专家和机器学习爱好者。 请在找到我原来的博客文章[An Average Joe](https://akshaysin.github.io/cors.html#.W23MxuhKhPY) 114 | 115 | Akshay -------------------------------------------------------------------------------- /JavaScript是如何工作:系列一.md: -------------------------------------------------------------------------------- 1 | # JavaScript是如何工作的:引擎,运行时以及调用栈的概述 2 | 3 | > 原文:[How JavaScript works: an overview of the engine, the runtime, and the call stack](https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 随着 JavaScript 变得越来越流行,团队在多个层级都对它进行利用-前端,后端,混合应用,嵌入式设备以及更多。 12 | 13 | 正如 [GitHut stats](http://githut.info/) 所展示的那样,JavaScript 是 Github 上面最活跃以及总 Push 次数最多的语言。在其它类别中也不会落后太多。 14 | ![](https://cdn-images-1.medium.com/max/3036/1*Zf4reZZJ9DCKsXf5CSXghg.png) 15 | 16 | 17 | ([获取最新的 GitHub language stats](https://madnight.github.io/githut/)). 18 | 19 | 如果项目对于 JavaScript越来越依赖,这意味着为了构建好的软件开发者必须利用这个 JS 提供的一切并且对于生态系统的内部有着更深的理解。 20 | 21 | 因此,尽管每天有很多开发者在使用 JavaScript,但并不知道内部到底发生了什么。 22 | 23 | ## 概览 24 | 25 | 几乎每个人都已经听说过V8引擎的概念,并且很多知道 JavaScript 是单线程的或者它是使用一个回调队列的。 26 | 27 | 在这篇博文中,我们将会详细讲述所有概念并且解释 JavaScript 是如何真正运行的。在了解这些细节之后,你将能够写出能够适宜地利用提供的 API 的更好的,非阻塞的 app。 28 | 29 | 如果对于 JavaScript 来说还不是很了解,这篇博文将会帮助你理解为什么 JavaScript 和别的语言相比如此“奇怪”。 30 | 31 | 如果你是一个有经验的 JavaScript 开发者,希望这篇文章能够让你对你每天使用的 JavaScript Runtime 是如何真正工作的。 32 | 33 | ## **JavaScript 引擎** 34 | 35 | 最流行的 JavaScript 引擎的例子之一就是谷歌的 V8 引擎。比如 Chrome 以及 Node.js 内部就是使用 V8 引擎。下面是一个简单的视图示例: 36 | 37 | ![](https://cdn-images-1.medium.com/max/2048/1*OnH_DlbNAPvB9KLxUCyMsA.png) 38 | 39 | 引擎主要由两个部分组成: 40 | 41 | * 内存堆——这是内存分配发生的地方 42 | * 回调——这是你代码执行时的栈帧。 43 | 44 | ## **Runtime** 45 | 46 | 有很多浏览器中的API几乎都被JavaScript开发者使用过(比如:'setTimeout')。然而这些API并不是由引擎提供的。 47 | 48 | 那么,它们是从哪来的呢? 49 | 50 | 事实证明这有一点复杂。 51 | 52 | ![](https://cdn-images-1.medium.com/max/2048/1*4lHHyfEhVB0LnQ3HlhSs8g.png) 53 | 54 | 因此,虽然我们有引擎但实际上是有更多。我们有那些由浏览器提供的 Web API,像 DOM, AJAX, setTimeout 以及更多。 55 | 56 | 接着,我们还有非常流行的**事件循环(event loo)**以及**回调队列(callback queue)**。 57 | 58 | ## 调用栈 59 | 60 | JavaScript 是一种单线程的编程语言,这意味着它只拥有一个单独的调用栈。因此它一次只能做一件事情。 61 | 62 | 调用栈是一种数据结构记录着我们正在程序的什么地方。如果我们步入一个函数,我们就将这个函数放在栈的顶部。如果我们从一个函数返回,我们则是将这个函数从栈顶弹出。这就是这个栈所做的一切。 63 | 64 | 让我们看一个例子。参看如下代码: 65 | 66 | ```javascript 67 | function multiply(x, y) { 68 | return x * y; 69 | } 70 | 71 | function printSquare(x) { 72 | var s = multiply(x, x); 73 | console.log(s); 74 | } 75 | 76 | printSquare(5); 77 | ``` 78 | 79 | 当引擎执行这段代码的时候,调用栈首先将会是空的。然后,将会按照以下步骤进行: 80 | 81 | ![](https://cdn-images-1.medium.com/max/2048/1*Yp1KOt_UJ47HChmS9y7KXw.png) 82 | 83 | 调用栈中的每一项都被称为**栈帧(Stack Frame)**。 84 | 85 | 并且这正是都异常被抛出的时候栈追踪是如何构建的——这基本就是异常发生时调用栈的状态。请看如下代码: 86 | 87 | ```javascript 88 | function foo() { 89 | throw new Error('SessionStack will help you resolve crashes :)'); 90 | } 91 | 92 | function bar() { 93 | foo(); 94 | } 95 | 96 | function start() { 97 | bar(); 98 | } 99 | 100 | start(); 101 | ``` 102 | 103 | 如果这段代码在Chrome中执行(假设代码是在一个叫做foo.js的文件中),接下来的栈追踪将会产生: 104 | 105 | ![](https://cdn-images-1.medium.com/max/2000/1*T-W_ihvl-9rG4dn18kP3Qw.png) 106 | 107 | “**爆栈**"——当你达到最大调用栈的大小的时候就会发生这种情况。并且这种情况很容易产生,特别是你没有对你的代码做全面的测试的时候。请看下面的示例代码: 108 | 109 | ```javascript 110 | function foo() { 111 | foo(); 112 | } 113 | 114 | foo(); 115 | ``` 116 | 117 | 当引擎开始执行这段代码的时候,它一开始调用函数”foo“。然而,这个函数递归调用本身并且没有终止条件。因此在每一个执行的步骤中,相同的函数都会一次又一次地被添加到调用栈中。看起来就像这样: 118 | 119 | ![](https://cdn-images-1.medium.com/max/2048/1*AycFMDy9tlDmNoc5LXd9-g.png) 120 | 121 | 在某个点,然而函数调用的数量就超过调用栈的实际尺寸,那么浏览器就决定采取行动,抛出一个错误,看起来是这个样子的: 122 | 123 | ![](https://cdn-images-1.medium.com/max/2000/1*e0nEd59RPKz9coyY8FX-uw.png) 124 | 125 | 在单线程环境中运行代码可能相当容易因为你不需要处理多线程环境中复杂的情形——比如,死锁。 126 | 127 | 但是在单线程环境中也可能遇到种种限制。因为 JavaScript 具有一个单独的调用栈,**当事情变得缓慢的时候到底发生了什么?** 128 | 129 | ## **并发以及事件循环** 130 | 131 | 当你的函数调用在调用栈中花了大量的时间来进行到底发生了什么?比如,想象一下假如你想在浏览器中使用 JavaScript 来做一些复杂的图像转换。 132 | 133 | 你可能会问——为什么这也会是一个问题?问题是尽管调用栈具有函数来执行,但是浏览器实施中不能做任何其他的事——它被阻塞了。这意味着浏览器不能渲染,它不能运行其他的代码,它就是歇菜了。如果你希望你的 app 能够具有流畅的 UI 的时候就会产生问题。 134 | 135 | 并且这不是唯一的问题。一旦你的浏览器开始处理调用栈中的大量任务,他将在很长时间内都无法响应。大多数浏览器通过抛出错误来采取行动,询问你是否想中止网页。 136 | 137 | ![](https://cdn-images-1.medium.com/max/2000/1*WlMXK3rs_scqKTRV41au7g.jpeg) 138 | 139 | 现在,这并不是一种最好的用户体验,是不是? 140 | 141 | 因此,我们如何在不阻塞UI并且让浏览器保持响应的情况下执行大量的代码?解决方案就是**异步回调**。 142 | 143 | 这个将会在”JavaScript是如何工作的"的第二部分进一步解释。 144 | 145 | 同时,如果你很难在你的JavaScript重现并且理解问题的时候,可以看看 [SessionStack](https://www.sessionstack.com)。SessionStack记录了你的web应用中的一切:所有的DOM变化,用户交互,JavaScript异常,栈追踪,失败的网络请求以及调试消息。 146 | 147 | 使用 SessionStack,你可以重现你的web应用中的问题就像录像一样,并且可以看到用户交互的一切。 148 | 149 | 现在有一个免费的计划能够允许你可以[开始免费试用](https://www.sessionstack.com/signup/) 150 | 151 | ![](https://cdn-images-1.medium.com/max/2062/1*kEQmoMuNBDfZKNSBh0tvRA.png) 152 | -------------------------------------------------------------------------------- /mst-codeql.md: -------------------------------------------------------------------------------- 1 | # 微软开源对于 Solorigate 活动捕获的开源 CodeQL 查询 2 | 3 | >原文:[微软 open sources CodeQL queries used to hunt for Solorigate activity](https://www.microsoft.com/security/blog/2021/02/25/microsoft-open-sources-codeql-queries-used-to-hunt-for-solorigate-activity/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | Solorigate 攻击的一个关键方面是供应链攻击,这使攻击者可以修改 SolarWinds Orion 产品中的二进制文件。这些经过修改的二进制文件是通过以前合法的更新渠道分发的,并允许攻击者远程执行恶意活动,例如窃取凭据,提权和横向移动,以窃取敏感信息。该事件提醒组织不仅要考虑是否准备好应对复杂的攻击,还需要考虑自己代码库的弹性。 12 | 13 | 微软坚信以透明的方式进行领导并与社区共享情报,从而改善整个行业的安全实践和状况。在此博客中,我们将分享审查代码库的过程,重点介绍一种特定的技术:使用 [CodeQL](https://securitylab.github.com/tools/codeql) 查询来大规模分析我们的源代码,并排除存在代码级别的危威胁情报(IoCs)和与 Solorigate 相关的代码模式。我们正在将本次本调查中使用的 [CodeQL 查询](https://github.com/github/codeql/pull/5083)开源,以便其他组织可以执行类似的分析。请注意,我们在此博客中介绍的查询仅可用于查找与 Solorigate 植入程序中的源代码具有相似之处的源代码,无论是在语法元素(名称,字面量等)还是功能上。两者可能在良性代码中同时发生,因此所有发现都需要进行审查以确定它们是否可行。此外,不能保证恶意行为者在其他操作中被约束为相同的功能或编码风格,因此这些查询可能无法检测到与在 Solorigate 植入代码中看到的策略有明显差异的其他植入代码。这些应被视为只针对攻击[审计技术](https://techcommunity.microsoft.com/t5/azure-sentinel/solarwinds-post-compromise-hunting-with-azure-sentinel/ba-p/1995095)的一部分。 14 | 15 | 长期以来,微软一直采用完整性控制来验证分发给我们的服务器和客户的最终编译二进制文件在开发和发布周期的任何时候都没有被恶意修改。例如,我们验证编译器生成的源文件哈希是否与原始源文件匹配。尽管如此,在微软,我们仍然秉承 “assume breach” 的理念,该理念告诉我们,无论我们的安全实践多么勤奋和广泛,潜在的对手都可以同样地聪明并拥有大量资源。作为 Solorigate 调查的一部分,我们使用了自动和手动技术来验证我们的源代码,构建环境以及生产二进制文件和环境的完整性。 16 | 17 | 微软在 Solorigate 调查期间的贡献反映了我们对 [Githubification of InfoSec](https://medium.com/@johnlatwc/the-githubification-of-infosec-afbdbfaad1d1) 中描述的基于社区的共享愿景的承诺。为了保持我们对防御者知识的了解并加快社区对复杂威胁的响应的愿景,微软团队在此次事件期间公开透明地共享了[威胁情报](https://techcommunity.microsoft.com/t5/azure-active-directory-identity/understanding-quot-solorigate-quot-s-identity-iocs-for-identity/ba-p/2007610),[详细的攻击分析和 MITER ATT&CK 技术](https://www.microsoft.com/security/blog/2020/12/18/analyzing-solorigate-the-compromised-dll-file-that-started-a-sophisticated-cyberattack-and-how-microsoft-defender-helps-protect/),[高级狩猎查询](https://techcommunity.microsoft.com/t5/azure-sentinel/solarwinds-post-compromise-hunting-with-azure-sentinel/ba-p/1995095),[事件响应指南](https://www.microsoft.com/security/blog/2020/12/21/advice-for-incident-responders-on-recovery-from-systemic-identity-compromises/)以及[风险评估工作簿](https://techcommunity.microsoft.com/t5/azure-active-directory-identity/azure-ad-workbook-to-help-you-assess-solorigate-risk/ba-p/2010718)。微软鼓励其他安全组织开源自己的威胁知识和防御者技术来共享 “Githubification” 愿景,以加速防御者的洞察力和分析。如前所述,我们已在 https://aka.ms/solorigate 上收集了全面的资源,以提供有关攻击的技术详细信息,威胁情报和产品指南。作为微软全面调查 Solorigate 的一部分,我们检查了自己的环境。正如我们之前所[分享](https://msrc-blog.microsoft.com/2020/12/31/microsoft-internal-solorigate-investigation-update/)的那样,这些调查发现有少量内部帐户存在活动,并且一些帐户已用于查看源代码,但是我们没有发现任何对源代码,构建基础结构,已编译的二进制文件或生产环境进行任何修改的[证据](https://www.microsoft.com/security/blog/2021/02/18/turning-the-page-on-solorigate-and-opening-the-next-chapter-for-the-security-community/)。 18 | 19 | ## CodeQL 入门以及微软如何使用它 20 | 21 | [CodeQL](https://securitylab.github.com/tools/codeql) 是一种功能强大的语义代码分析引擎,现在已经是 GitHub 的一部分。与许多分析解决方案不同,它在两个不同的阶段工作。首先,作为将源代码编译为二进制文件的一部分,CodeQL 建立了一个捕获编译代码模型的数据库。对于解释型语言,由于没有编译器,因此它将解析源并构建自己的抽象语法树模型。其次,该数据库一旦构建,便可以像其他任何数据库一样反复查询。CodeQL 语言是专用于构建可轻松从数据库中选择复杂的代码条件。 22 | 23 | 在微软我们发现 CodeQL 中发现如此多的实用性的原因之一,尤其是因为这种两阶段的方法释放了许多有用的场景,包括不仅可以将静态分析用于主动安全开发生命周期分析,而且还可以用于整个企业的反应性代码检查。我们将微软的各种构建系统或管道生成的 CodeQL 数据库聚合到一个集中式基础结构中,在该基础结构中,我们能够立即查询整个 CodeQL 数据库的范围。聚合 CodeQL 数据库使我们能够在众多代码库中进行语义搜索,并根据构建的一部分特定代码查找可能跨越多个程序集,库或模块的代码条件。我们拥有可以在描述的变体后数小时内分析成千上万的资源库的能力,以查找新描述的漏洞变体,但是它也使我们能够同样快速地对 Solorigate 植入模式进行首次通过调查。 24 | 25 | ![](https://www.microsoft.com/security/blog/wp-content/uploads/2021/02/Figure-1b-process.png) 26 | 27 | 我们正在开源这些代码级威胁情报的多个 C# 查询,目前可以在 [CodeQL GitHub 代码仓库](https://aka.ms/Solorigate-CodeQL-Queries)中找到它们。该仓库中的 [Solorigate-Readme.md](https://aka.ms/Solorigate-CodeQL-ReadMe) 包含每个查询的详细说明以及每个查询试图查找的代码级威胁情报。它还包含给其他查询作者的指南,这些指南涉及对那些查询进行调整或编写在查找模式时采用不同策略的查询。 28 | 29 | GitHub 即将发布有关如何为现有 CodeQL 客户部署这些查询的指南。提醒一下,CodeQL 对于 GitHub 托管的开源项目是免费的。 30 | 31 | ## 我们使用 CodeQL 寻找代码级威胁情报的方法 32 | 33 | 在寻找代码级 Solorigate 威胁情报时,我们使用了两种不同的策略。一种方法是寻找在 Solorigate 代码级威胁情报中脱颖而出的特定语法。另一种方法则针对代码级威胁情报中存在的技术寻找整体语义模式。 34 | 35 | 与可比较的正则表达式搜索相比具有很多优势,语法查询的编写和执行速度非常快。但是,它们对于恶意角色更改其使用的名称和字面量很弱。语义模式寻找植入程序中使用的总体技术,例如哈希处理名称,联系 C2 服务器之前的时间延迟等。这些可以承受实质性的变化,但是它们在编写时更加复杂并且在一次分析很多代码库时更加耗费计算资源。 36 | 37 | ![](https://www.microsoft.com/security/blog/wp-content/uploads/2021/02/Figure-2a-sample-code.png) 38 | 39 | 通过组合这两种方法,查询能够检测到恶意行为者更改了技术但使用了相似语法,或者更改了语法但采用了相似技术的场景。由于恶意行为者可能会更改语法和技术,因此 CodeQL 只是我们大量调查工作的一部分。 40 | 41 | ## 使用 CodeQL 的下一步 42 | 43 | 我们在此博客中共享并在 [Solorigate-Readme.md](https://aka.ms/Solorigate-CodeQL-ReadMe) 目标模式中描述特别与 Solorigate 代码级威胁情报相关联的查询,但 CodeQL 还提供了许多其他选项来查询后门功能和逃避检测技术。 44 | 45 | 这些查询的编写速度相对较快,与使用源代码的文本搜索相比,我们能够在我们的 CodeQL 数据库中更准确地寻找模式,并且用更少的精力手动审查发现的结果。CodeQL 是一个功能强大的开发人员工具,我们希望这篇文章能激发组织探索如何使用它来改善反应式安全响应并充当入侵检测工具。 46 | 47 | 在以后的博客文章中,我们将分享微软使用 CodeQL 的更多方式。我们还将继续在CodeQL的基础上进行开放源代码的查询和实用程序,以便其他人可以从中受益并进一步建立在它们之上。 48 | 49 | -------------------------------------------------------------------------------- /Chrome 0-day 漏洞.md: -------------------------------------------------------------------------------- 1 | # Operation WizardOpium 攻击使用的 Chrome 零日漏洞 CVE-2019-13720 2 | 3 | >原文:[Chrome 0-day exploit CVE-2019-13720 used in Operation WizardOpium](https://securelist.com/chrome-0-day-exploit-cve-2019-13720-used-in-operation-wizardopium/94866/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ## 摘要 12 | 13 | 卡巴斯基安全防护是卡巴斯基产品的一部分,过去已成功检测到许多零日攻击。最近,为 Google的 Chrome 浏览器发现了一个未知的新漏洞。我们会立即将此情况报告给 Google Chrome 安全团队。在审核了我们提供的 PoC 之后,Google 确认存在零日漏洞并将其分配为 CVE-2019-13720。 Google 已针对 Windows,Mac 和 Linux 发布了 Chrome 版本78.0.3904.87,我们建议所有 Chrome 用户尽快将其更新为最新版本!你可以点击[此处](https://chromereleases.googleblog.com/2019/10/stable-channel-update-for-desktop_31.html)阅读 Google 公告。 14 | 15 | 卡巴斯基端点产品借助漏洞利用防御组件检测漏洞。该攻击的裁决是 Exploit.Win32.Generic。 16 | 17 | 我们称这些攻击为 Operation WizardOpium。到目前为止,我们还无法与任何已知的威胁者建立明确的联系。与蓝莲花攻击有某些非常弱的代码相似性,尽管这很可能是 false flag。目标网站的配置与最近部署了类似虚假标记攻击的早期 [DarkHotel](https://securelist.com/the-darkhotel-apt/66779/) 攻击更加一致。 18 | 19 | 卡巴斯基情报报告的客户可以获取有关 CVE-2019-13720 和最近的 DarkHotel 的 false flag 攻击的详细信息。有关更多信息,请联系:intelreports@kaspersky.com。 20 | 21 | ## 技术细节 22 | 23 | 攻击利用朝鲜语新闻门户上的水坑式注入。在主页中插入了恶意的 JavaScript 代码,恶意代码又从远程站点加载了分析脚本。 24 | 25 | ![KL1Qk8.png](https://s2.ax1x.com/2019/11/02/KL1Qk8.png) 26 | 27 | **重定向到漏洞利用登录页面** 28 | 29 | 主页上托管了一个从 hxxp://code.jquery.cdn.behindcorona[.]com/ 中加载了远程脚本的微不足道的 JavaScript 标签。 30 | 31 | 然后,该脚本将加载另一个名为 .charlie.XXXXXXXX.js 的脚本。该 JavaScript 通过与浏览器的用户代理进行比较来检查受害者的系统是否能被感染,程序应在 64位 版本的 Windows 上运行,而不是 WOW64 进程;它还尝试获取浏览器的名称和版本。该漏洞试图利用 Google Chrome 浏览器中的 bug,脚本会检查该版本是否大于或等于65(当前的Chrome版本为78): 32 | 33 | ![KLMwkD.png](https://s2.ax1x.com/2019/11/02/KLMwkD.png) 34 | 35 | **分析脚本(.charlie.XXXXXXXX.js)中 Chrome 版本检测** 36 | 37 | 如果检测出浏览器版本,脚本将开始向攻击者的受控服务器 (behindcorona[.]com) 发送一些 AJAX 请求,其中路径名指向传递给脚本(xxxxxxx.php)的参数。首先需要获得一些将来有用的重要信息。该信息包括几个十六进制编码的字符串,这些字符串告诉脚本应从服务器下载多少个实际漏洞利用代码,以及图像文件的 URL,这个图片嵌入了最终载荷的密钥和RC4密钥从而对漏洞利用代码解密。 38 | 39 | ![KLM0te.png](https://s2.ax1x.com/2019/11/02/KLM0te.png) 40 | 41 | **漏洞利用链– AJAX 请求 xxxxxxx.php** 42 | 43 | 下载完所有代码块后,RC4 脚本将所有部分解密并拼接在一起,这为攻击者提供了一个包含完整浏览器漏洞的新 JavaScript 代码。为了解密这些部分,使用了之前的 RC4 密钥。 44 | 45 | ![KLMgnP.png](https://s2.ax1x.com/2019/11/02/KLMgnP.png) 46 | 47 | **另一次版本检测** 48 | 49 | 浏览器漏洞脚本被混淆;消除混淆后我们观察到一些奇怪的事情: 50 | 51 | 1. 对用户代理的字符串进行另一项检查–这次它检查浏览器版本是 76 还是77。这可能意味着漏洞利用作者仅使用这些版本(先前的漏洞利用阶段检查的版本号为65或更高)或过去使用曾在旧版 Chrome 中使用过其他漏洞利用。 52 | 53 | ![KLM4hQ.png](https://s2.ax1x.com/2019/11/02/KLM4hQ.png) 54 | 55 | **混淆后的漏洞利用代码** 56 | 57 | 2. 操作浏览器的内置 BigInt 类,这个类在 JavaScript 代码中执行 64 位算术很有用,例如,在 64位 环境中使用原生指针。通常情况下,漏洞利用开发者通过与32位数字实现自己的功能。但是,在这种情况下,使用的是BigInt,它应该更快,因为它是在浏览器的代码中本地实现的。漏洞利用开发者此处并未使用全部 64 位,而是使用较小的数字范围。这就是为什么它们实现一些功能以与数字的较高/较低部分兼容原因。 58 | 59 | ![KLMqBV.png](https://s2.ax1x.com/2019/11/02/KLMqBV.png) 60 | 61 | **使用 64 位数字的代码片段** 62 | 63 | 3. 在实际的代码中有许多未使用的函数和变量。这通常意味着它们用于调试代码,然后在将代码移至生产环境时被遗忘。 64 | 65 | 4. 大多数代码使用与浏览器的某些易受攻击组件相关的几个类。由于此 bug 仍未得到修复,因此我们此处不包括有关特定易受攻击组件的详细信息。 66 | 67 | 5. 有一些带有数字的大数组,这些数字代表一个 shellcode块 和一个嵌入式 PE 镜像。 68 | 69 | 由于存在漏洞披露原则,我们在此提供的分析特意简短。该漏洞利用了两个线程之间的竞争条件错误,原因是它们之间缺少适当的同步。它使攻击者处于释放后使用(UaF)的状态,这是非常危险的,因为它可能导致代码执行,这正是本例所发生的情况。 70 | 71 | 该漏洞利用程序首先尝试触发 UaF 对重要的64位地址(作为指针)执行信息泄漏。结果是:1)如果地址成功泄漏,则表明漏洞利用正常。2)泄漏的地址用于定位堆/栈的位置,这使地址空间布局随机化(ASLR)技术无效; 3)通过在该地址附近进行搜索,可以找到其他一些有用的指针,以供进一步利用。 72 | 73 | 之后,它尝试使用递归函数创建一堆大对象。这样做是为了确定一些重要的的堆布局,这对于成功利用漏洞很重要。同时,它尝试利用堆喷涂技术,该技术旨在重用先前在 UaF 部分释放的指针。尽管实际上它们位于相同的内存区域,但该技巧可能会引起混乱,并使攻击者能够对两个不同的对象进行操作(从 JavaScript 代码的角度来看)。 74 | 75 | 该漏洞尝试执行许多操作来分配/释放内存以及其他技术,这些技术最终为攻击者提供了任意的读/写能力。这用于制作可以与 WebAssembly 和 FileReader 一起使用的特殊对象来执行嵌入的 Shellcode 有效载荷。 76 | 77 | ![KLML7T.png](https://s2.ax1x.com/2019/11/02/KLML7T.png) 78 | 79 | **第一阶段 shellcode** 80 | 81 | ## 有效载荷说明 82 | 83 | 最终的有效载荷将作为加密的二进制文件(worst.jpg)下载,并由shellcode解密。 84 | 85 | ![KLQPnx.png](https://s2.ax1x.com/2019/11/02/KLQPnx.png) 86 | 87 | **加密的有效载荷– Worst.jpg** 88 | 89 | 解密后,恶意软件模块将作为 updata.exe 拖放到磁盘上并执行。 为了持久化,该恶意软件会在 Windows Task Scheduler 中安装任务。 90 | 91 | 有效载荷“安装程序”是 RAR SFX 归档文件,其中包含以下信息: 92 | 93 | File size: 293,403 94 | MD5: 8f3cd9299b2f241daf1f5057ba0b9054 95 | SHA256: 35373d07c2e408838812ff210aa28d90e97e38f2d0132a86085b0d54256cc1cd 96 | 97 | 这个文档包含两个文件: 98 | ![KLQe9H.png](https://s2.ax1x.com/2019/11/02/KLQe9H.png) 99 | 100 | 文件名: iohelper.exe 101 | 102 | MD5: 27e941683d09a7405a9e806cc7d156c9 103 | SHA256: 8fb2558765cf648305493e1dfea7a2b26f4fc8f44ff72c95e9165a904a9a6a48 104 | 105 | 文件名: msdisp64.exe 106 | 107 | MD5: f614909fbd57ece81d00b01958338ec2 108 | SHA256: cafe8f704095b1f5e0a885f75b1b41a7395a1c62fd893ef44348f9702b3a0deb 109 | 110 | 这两个文件是同时编译的,我们确信的依据是时间戳 "Tue Oct 8 01:49:31 2019”。 111 | 112 | 主模块(msdisp64.exe)尝试从硬编码的 C2 服务器集中下载下一部分。下一部分位于 C2 服务器上具有受害计算机名称的文件夹中,因此威胁执行者可以了解有关哪些计算机被感染的信息,并将下一阶段模块放置在 C2 服务器上的特定文件夹中。 113 | 114 | 卡巴斯基情报报告的客户可以获取有关此攻击的更多详细信息。更多信息,请联系:intelreports@kaspersky.com。 115 | 116 | ## IoCs 117 | 118 | * behindcorona[.]com 119 | * code.jquery.cdn.behindcorona[.]com 120 | * 8f3cd9299b2f241daf1f5057ba0b9054 121 | * 35373d07c2e408838812ff210aa28d90e97e38f2d0132a86085b0d54256cc1cd 122 | * 27e941683d09a7405a9e806cc7d156c9 123 | * 8fb2558765cf648305493e1dfea7a2b26f4fc8f44ff72c95e9165a904a9a6a48 124 | * f614909fbd57ece81d00b01958338ec2 125 | * cafe8f704095b1f5e0a885f75b1b41a7395a1c62fd893ef44348f9702b3a0deb 126 | * kennethosborne@protonmail.com 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /你应该了解的5个 Logstash Filter 插件.md: -------------------------------------------------------------------------------- 1 | # 你应该了解的5个 Logstash Filter 插件 2 | 3 | > 原文:[5 Logstash Filter Plugins You Need to Know About](https://logz.io/blog/5-logstash-filter-plugins/#ult-fs-search) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![logstash filter](https://logz.io/wp-content/uploads/2017/08/logstash_filter2.jpg) 12 | 13 | 在 [ELK](https://logz.io/learn/complete-guide-elk-stack/) 中, Logstash 处理资源繁重的日志聚合和处理的任务。 Logstash 执行的处理工作确保我们的日志消息被正确解析和结构化,并且这种结构使你能够更容易地在 Elasticsearch 中进行索引分析和数据可视化。 14 | 15 | 对数据执行什么精确处理由你在 Logstash 配置文件的 filter 部分确定。 在本节中,你可以从大量的官方支持和社区 filter 插件中选择从而决定如何转换日志。 最常用的过滤器插件是 grok,但是还有一些其他非常有用的插件可以使用。 16 | 17 | 你使用的插件当然取决于日志本身,但本文尝试列出你最有可能在涉及 Logstash 的任何日志处理中找到的五个插件。 18 | 19 | ## # 1 grok 20 | 21 | 如上所述,grok 是 Logstash 中最常用的过滤器插件。 尽管事实上它不容易使用,但是 grok 非常受欢迎,因为它允许你将非结构化日志结构化。 22 | 23 | 以下面的随机日志消息为例: 24 | 25 | ``` 26 | 2016-07-11T23:56:42.000+00:00 INFO 27 | [MySecretApp.com.Transaction.Manager]:Starting transaction for session 28 | -464410bf-37bf-475a-afc0-498e0199f00 29 | ``` 30 | 31 | 我们使用的 grok 正则就跟下面一样: 32 | 33 | ``` 34 | filter { 35 | grok { 36 | match => { "message" =>"%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:log-level} [%{DATA:class}]:%{GREEDYDATA:message}" } 37 | } 38 | } 39 | ``` 40 | 41 | 处理之后,日志消息就会处理成下面这样: 42 | 43 | ``` 44 | { 45 | "timestamp" => "2016-07-11T23:56:42.000+00:00", 46 | "log-level" =>"INFO", 47 | "class" =>"MySecretApp.com.Transaction.Manager" 48 | "message" => "Starting transaction for session -464410bf-37bf-475a-afc0-498e0199f008" 49 | } 50 | ``` 51 | 52 | 这就是 Elasticsearch 如何索引日志消息。 以此格式排序,日志消息已被分解成逻辑命名的字段,可以更容易地查询,分析和可视化。 53 | 54 | 在[这篇文章中](https://logz.io/blog/logstash-grok/)可以找到更多关于 grok 如何工作和使用的信息。 55 | 56 | ## # 2 mutate 57 | 58 | 另一个常见的 Logstash filter 插件是 *mutate*。 顾名思义,这个 filter 允许你通过“改变”各个字段真正地转换你的日志消息。 例如,你可以使用 filter 来更改字段,将它们拼接在一起,重命名它们等等。 59 | 60 | 使用上面的日志作为示例,使用 *mutate* 插件的 *lowercase* 配置选项,我们可以将“log-level”字段转换为小写: 61 | 62 | ``` 63 | filter { 64 | grok {...} 65 | mutate { lowercase => [ "log-level" ] } 66 | } 67 | ``` 68 | 69 | mutate 插件是更改日志格式的好方法。 [这里](https://www.elastic.co/guide/en/logstash/current/plugins-filters-mutate.html)列出了插件的不同配置选项的完整列表。 70 | 71 | ## # 3 date 72 | 73 | 如果分析日志和事件未按时间顺序排列怎么办? 74 | 75 | Logstash *date* filter 插件可用于从日志消息中提取时间和日期,并将其定义为日志的时间戳字段(@timestamp)。 一旦定义,这个时间戳字段将以正确的时间顺序排列日志,并帮助你更有效地分析它们。 76 | 77 | 有几十种(如果不是数百种)不同的方式可以在日志中格式化时间和日期。 78 | 79 | 以下是Apache访问日志的示例: 80 | 81 | ``` 82 | 200.183.100.141 - - [25/Nov/2016:16:17:10 +0000] "GET 83 | /wp-content/force-download.php?file=../wp-config.php HTTP/1.0" 200 84 | 3842 "http://hack3r.com/top_online_shops" "Mozilla/4.0 (compatible; 85 | MSIE 8.0; Windows NT 5.1; Trident/4.0; YTB720; GTB7.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" 86 | ``` 87 | 88 | 使用 date filter 如下,我们可以提取日期和时间正则,并将其定义为@timestamp字段,并根据此所有日志将按以下排序: 89 | 90 | ``` 91 | filter { 92 | grok { 93 | match => { "message" => "%{COMBINEDAPACHELOG}"} 94 | } 95 | date { 96 | match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"] 97 | target => "@timestamp" } 98 | } 99 | ``` 100 | 101 | 请注意,如果不使用日期过滤器,Logstash将根据输入时间自动设置时间戳。 102 | 103 | 在[这里](https://www.elastic.co/guide/en/logstash/5.4/plugins-filters-date.html)阅读有关其他配置选项。 104 | 105 | ## # 4 json 106 | 107 | [JSON](http://www.json.org/) 是一种非常受欢迎的日志格式,因为它允许用户编写可以轻松读取和分析的结构化和标准化的消息。 108 | 109 | 为了维护整个消息或特定字段的 JSON 结构,Logstash *json* filter 插件使你能够在日志消息中提取和维护 JSON 数据结构。 110 | 111 | 下面的示例是一个格式为 JSON 的 Apache 访问日志: 112 | 113 | ``` 114 | { 115 | "time":"[30/Jul/2017:17:21:45 +0000]", 116 | "remoteIP":"192.168.2.1", 117 | "host":"my.host.local", 118 | "request":"/index.html", 119 | "query":"", 120 | "method":"GET", 121 | "status":"200", 122 | "userAgent":"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; YTB720; GTB7.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)", "referer":"-" 123 | } 124 | ``` 125 | 126 | 我们可以使用 json filter 来保留数据结构,而不是将日志平铺成一行: 127 | 128 | ``` 129 | filter { json { source =>"message" target => "log" } } } 130 | ``` 131 | 132 | source 配置选项定义日志中的哪个字段是你要解析的 JSON。 在这个例子中,整个消息字段是一个 JSON。 我还使用目标选项将 JSON 扩展为名为 log 的字段中的数据结构。 133 | 134 | 在[这里](https://www.elastic.co/guide/en/logstash/5.4/plugins-filters-json.html)阅读有关其他配置选项。 135 | 136 | ## # 5 kv 137 | 138 | 键值对或 KVP 是另一种常用的日志格式。 像 JSON 一样,这种格式主要是因为它是可读的,Logstash kv filter 插件允许你自动解析消息或以这种方式格式化的特定字段。 139 | 140 | 以此日志为例: 141 | 142 | ``` 143 | 2017-07025 17:02:12 level=error message="connection refused" service="listener" thread=125 customerid=776622 ip=34.124.233.12 queryid=45 144 | ``` 145 | 146 | 我可以使用以下 kv filter 来指示 Logstash 如何处理它: 147 | 148 | ``` 149 | filter { 150 | kv { 151 | source => "metadata" 152 | trim => "\"" 153 | include_keys => [ "level","service","customerid",”queryid” ] 154 | target => "kv" 155 | } 156 | } 157 | ``` 158 | 159 | 请注意配置选项的使用。 我正在使用 source 来定义字段来执行 key = value 搜索,trim 以忽略特定字符,include_keys指定应该添加到日志中的解析 key,并且定位到所有 key 对象的容器, 再放入值。 160 | 161 | 在[这里](https://www.elastic.co/guide/en/logstash/5.4/plugins-filters-kv.html#plugins-filters-kv-target)阅读有关其他配置选项。 162 | 163 | ## 总结 164 | 165 | 正如我在文章开头所说,有大量的 Logstash filter 插件可供你使用。 你使用哪一个当然取决于您要处理的具体日志消息。 166 | 167 | 值得一提的其他非常有用的过滤器插件是 geoip(用于添加IP字段的地理数据)和 csv(用于解析CSV日志)插件。 168 | 169 | 虽然这些插件中的每一个都是有用的,但是当它们一起用于解析日志时,它们的全部功能被释放。 实际上,在大多数情况下,你最有可能使用 grok 和至少一个或两个附加插件的组合。 这种组合使用将保证你的日志在 Logstash 的另一端完美格式化! 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /从仓库中移除敏感信息.md: -------------------------------------------------------------------------------- 1 | # 从仓库中移除敏感信息 2 | 3 | >原文:[Removing sensitive data from a repository](https://help.github.com/articles/removing-sensitive-data-from-a-repository/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 如果你将敏感数据(如密码或 SSH 密钥)提交到 Git 仓库,则可以将其从历史记录中删除。 要从仓库的历史记录中完全删除不需要的文件,你可以使用`git filter-branch`命令或 BFG Repo-Cleaner。 12 | 13 | `git filter-branch` 命令和 BFG Repo-Cleaner 会重写你的版本库的历史记录,这会更改你修改的现有提交和任何相关提交的SHA。更改的提交SHA可能会影响仓库中的打开请求。我们建议在从仓库中删除文件之前合并或关闭所有打开的请求。 14 | 15 | 你可以使用 `git rm` 从最新的提交中删除文件。 有关删除使用最新提交添加的文件的信息,请参阅“[从仓库历史记录中删除文件](https://help.github.com/articles/removing-files-from-a-repository-s-history)” 16 | 17 | > 警告:一旦你推送了一个提交到 GitHub,你应该考虑它包含的任何数据都会被泄露。如果你提交了密码,请更改密码!如果你提交了密钥,请生成一个新密钥。 18 | 19 | > 本文将告诉你如何使用 GitHub 仓库中的任何分支或标签无法访问敏感数据。然而,重要的是要注意到这些提交可能仍然可以在你的存储库的任何克隆或分支中直接通过它们在 GitHub上 的缓存视图中的 SHA-1 哈希以及通过引用它们的任何拉取请求来访问。你无法对仓库中的现有克隆或分支做任何事情,但可以通过联系[ GitHub 支持](https://github.com/contact),永久删除所有存储库的缓存视图并在GitHub上提出请求。 20 | 21 | ## 从仓库历史中清除文件 22 | ### 使用 BFG 23 | 24 | [BFG Repo-Cleaner](http://rtyley.github.io/bfg-repo-cleaner/) 和 `git filter-branch` 类似,用于删除不需要的文件,是一种更快速、更简单的替代方法。 例如,要删除含有敏感数据的文件并保持最新提交不变,运行: 25 | 26 | `bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA` 27 | 28 | 要替换 passwords.txt中 列出的所有文本,可以在仓库历史记录中找到它,运行: 29 | 30 | `bfg --replace-text passwords.txt` 31 | 32 | 有关完整的使用和下载说明,请参阅[BFG Repo-Cleaner](http://rtyley.github.io/bfg-repo-cleaner/)的文档。 33 | 34 | ### 使用 filter-branch 35 | > 警告:如果你在暂存(stash)更改后运行 `git filter-branch`,你将无法使用其他暂存命令检索你的更改。 在运行 `git filter-branch` 之前,我们建议不要修改你所做的任何更改。要取消最后一组隐藏的更改,请运行 `git stash show -p | git apply -R`。 有关更多信息,请参阅[Git Tools Stashing](https://git-scm.com/book/en/v1/Git-Tools-Stashing)。 36 | 37 | 为了说明 `git filter-branch` 如何工作,我们将向你展示如何从仓库的历史记录中删除具有敏感数据的文件,并将其添加到 `.gitignore` 中以确保它不会被意外重新提交。 38 | 39 | 1. 如果你的历史记录中尚未拥有敏感数据的存储库本地副本,请将[克隆仓库](https://help.github.com/articles/cloning-a-repository/)到本地 电脑。 40 | 41 | ```bash 42 | git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY 43 | Initialized empty Git repository in /Users/YOUR-FILE-PATH/YOUR-REPOSITORY/.git/ 44 | remote: Counting objects: 1301, done. 45 | remote: Compressing objects: 100% (769/769), done. 46 | remote: Total 1301 (delta 724), reused 910 (delta 522) 47 | Receiving objects: 100% (1301/1301), 164.39 KiB, done. 48 | Resolving deltas: 100% (724/724), done. 49 | ``` 50 | 51 | 2. 切换到仓库的工作目录。 52 | 53 | ``` 54 | cd YOUR-REPOSITORY 55 | ``` 56 | 57 | 3. 运行以下命令,用要删除的文件的**路径替换 `PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA`,而不仅仅是文件名**。 这些参数: 58 | 59 | * 强制 Git 处理但不检出每个分支和标签的整个历史记录 60 | * 移除指定的文件以及作为结果生成的任何空提交 61 | * **重写你现有的标签** 62 | 63 | ``` 64 | git filter-branch --force --index-filter \ 65 | 'git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' \ 66 | --prune-empty --tag-name-filter cat -- --all 67 | Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (266/266) 68 | Ref 'refs/heads/master' was rewritten 69 | ``` 70 | 71 | > 注意:如果包含敏感数据的文件曾经存在于任何其他路径(因为它已被移动或重命名),那么你也必须在这些路径上运行此命令。 72 | 73 | 4. 将含有敏感数据的文件添加到 `.gitignore`中,以确保你不会意外地再次提交。 74 | 75 | ``` 76 | echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore 77 | git add .gitignore 78 | git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore" 79 | [master 051452f] Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore 80 | 1 files changed, 1 insertions(+), 0 deletions(-) 81 | ``` 82 | 83 | 5. 仔细检查你是否已经从仓库的历史记录中删除了你想要的所有内容,并检查了所有分支。 84 | 85 | 6. 一旦对仓库的状态感到满意,强制推送本地更改以覆盖你的 GitHub 仓库以及你推送的所有分支: 86 | 87 | ``` 88 | git push origin --force --all 89 | Counting objects: 1074, done. 90 | Delta compression using 2 threads. 91 | Compressing objects: 100% (677/677), done. 92 | Writing objects: 100% (1058/1058), 148.85 KiB, done. 93 | Total 1058 (delta 590), reused 602 (delta 378) 94 | To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git 95 | + 48dc599...051452f master -> master (forced update) 96 | ``` 97 | 98 | 7. 为了从标签发布中删除敏感文件,你还需要强制推送您的 Git 标签: 99 | 100 | ``` 101 | git push origin --force --tags 102 | Counting objects: 321, done. 103 | Delta compression using up to 8 threads. 104 | Compressing objects: 100% (166/166), done. 105 | Writing objects: 100% (321/321), 331.74 KiB | 0 bytes/s, done. 106 | Total 321 (delta 124), reused 269 (delta 108) 107 | To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git 108 | + 48dc599...051452f master -> master (forced update) 109 | ``` 110 | 111 | 8. 告诉你的同事 [rebase](https://git-scm.com/book/en/Git-Branching-Rebasing) 而不是 merge 它们创建的任何分支,这些分支是从旧的(受污染的)存储库历史中创建的。一次合并提交可能会重新引入一些或所有你刚才去除清除问题的受污染历史记录。 112 | 113 | 经过一段时间,你确信 `git filter-branch` 没有意外的副作用,你可以强制你的本地仓库中的所有对象被解除引用和垃圾收集,使用下面的命令(使用Git 1.8.5或更新的版本): 114 | 115 | ``` 116 | git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin 117 | git reflog expire --expire=now --all 118 | git gc --prune=now 119 | Counting objects: 2437, done. 120 | Delta compression using up to 4 threads. 121 | Compressing objects: 100% (1378/1378), done. 122 | Writing objects: 100% (2437/2437), done. 123 | Total 2437 (delta 1461), reused 1802 (delta 1048) 124 | ``` 125 | 126 | > 注意:你也可以通过将已过滤的历史记录推送到新的或空的存储库,然后从GitHub创建新的克隆来实现此目的。 127 | 128 | ## 在未来避免意外的提交 129 | 有几个简单的技巧可以避免提交你不想提交的东西: 130 | 131 | * 使用 GitHub Desktop 或 gitk 等可视程序来提交更改。 可视化程序通常可以更容易地看到每个提交将会添加,删除和修改哪些文件。 132 | * 避免在命令行中使用 `git add .` 和` git commit -a` 这样的 catch-all 命令 - 改为使用 `git add filename` 和 `git rm filename` 来单独分级文件。 133 | * 使用 `git add --interactive` 在每个文件中分别查看和分级更改。 134 | * 使用 `git diff --cached` 来查看你为提交而进行的更改。 只要你不使用 `-a` 标志,`git commit` 就会产生确切的差异。 135 | -------------------------------------------------------------------------------- /使用ELK Stack建设SIEM.md: -------------------------------------------------------------------------------- 1 | # 使用ELK Stack建设SIEM 2 | 3 | >原文:[Using the ELK Stack for SIEM](https://logz.io/blog/elk-siem/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![](https://logz.io/wp-content/uploads/2018/06/using_the_elk_stack_for_siem_-_article.jpg) 12 | 13 | 任何 SIEM 系统的核心都是日志数据。有很多种。无论是来自服务器,防火墙,数据库还是网络路由器,日志都为分析人员提供了深入了解 IT 环境中发生事件的原始资料。 14 | 15 | 然而,在将这些材料转化为资源之前,需要采取几个关键步骤。数据需要收集,处理,规范化,增强和存储。这些步骤通常在术语“日志管理”下组合在一起,是任何 SIEM系统中必备的组件。 16 | 17 | 因此,ELK Stack 是当今世界上最流行的开源日志分析和管理平台,这绝非巧合,它是当前大多数[开源 SIEM 解决方案](https://logz.io/blog/open-source-siem-tools)的重要组成部分。 ELK 负责收集,分析,存储和分析,部分架构来源于 OSSEC Wazuh,SIEMonster 和 Apache Metron。 18 | 19 | 如果日志管理和日志分析是 SIEM 中唯一的组件,则 ELK Stack 可被视为有效的开源解决方案。但是当我们定义[SIEM 系统实际是什么](https://logz.io/blog/what-is-siem/)时,除了日志管理之外,还列出了很多组件列表。本文将尝试深入探讨 ELK Stack 是否可用于S IEM,缺少什么以及将其扩展到全功能 SIEM 解决方案所需的内容。 20 | 21 | 日志收集 22 | -------------- 23 | 24 | 如上所述,SIEM 系统涉及汇总来自多个数据源的数据。这些数据源将根据你的环境而有所不同,但很可能您将从你的应用程序,基础设施级别(例如服务器,数据库),安全控制(例如防火墙,VPN),网络基础设施(如路由器,DNS)外部安全数据库(例如威胁情报)。 25 | 26 | 这需要 ELK Stack 非常适合处理的聚合能力。使用[Beats](https://logz.io/blog/beats-tutorial/)和[Logstash](https://logz.io/blog/logstash-tutorial/)的组合,你可以构建日志记录体系结构由多个数据管道组成。 Beats 是轻量级日志转发器,可用作边缘主机上的代理来跟踪和转发不同类型的数据,最常见的 beat 是用于转发日志文件的 Filebeat。 Logstash 然后可用于聚合来自 beat 的数据,对其进行处理(见下文)并将其转发给流水线中的下一个组件。 27 | 28 | 由于涉及的数据量很大,并且需要挖掘不同的数据源,因此很可能需要多个 Logstash 实例来确保更具弹性的数据管道。不仅如此,还需要部署排队机制来确保处理数据突发,并且管道中各个组件之间的断开连接不会导致数据丢失。 Kafka 通常是在这种情况下使用的工具,在 Logstash 之前安装(其他工具,如 Redis 和 RabbitMQ 也被使用)。 29 | 30 | 因此,单独使用 ELK Stack 很可能不足以满足你的业务需求,并且其生成的数据也会增长。希望使用 ELK 进行 SIEM 的组织必须了解需要部署其他组件才能增加堆栈。 31 | 32 | 日志处理 33 | -------------- 34 | 35 | 收集数据并转发它当然只是 Logstash 在日志记录管道中的一部分。另一个关键任务,也是 SIEM中 非常重要的一个任务,就是处理和解析数据。 36 | 37 | 上面概述的所有数据源类型都以不同的格式生成数据。要在下一步中取得成功 - 即搜索数据和分析数据 - 数据需要进行标准化。这意味着将不同的日志消息分解为有意义的字段名称,在 Elasticsearch中 正确映射字段类型,并在必要时丰富特定字段。 38 | 39 | 人们不能忽略这一步骤的重要性。如果没有正确的解析,当你试图在 Kibana中 分析时,你的数据将毫无意义。 Logstash 是一个强大的工具,可以帮助你完成此关键任务。 Logstash 支持大量不同的过滤器插件,可以分解日志,使用地理信息丰富特定字段,例如,删除字段,添加字段等。 40 | 41 | 再一次,诸如 SIEM 系统所需的日志架构可能变得复杂。特别是,配置 Logstash 以处理各种日志类型将需要多个 Logstash 配置文件和 Logstash 实例。重复处理是复杂过滤器配置的结果,会影响 Logstash 性能。监控 Logstash 管道非常重要,监控 API(例如用于识别具有高 CPU 的 Java 线程的 Hot Thread API)可用于此目的。 42 | 43 | 存储和保留 44 | --------------------- 45 | 46 | 从不同数据源收集的日志数据需要存储在数据存储中。在使用 ELK 的情形下,[Elasticsearch](https://logz.io/blog/elasticsearch-tutorial/)扮演数据索引和存储的角色。 47 | 48 | Elasticsearch 是目前最流行的数据库之一,事实上 - 它是 Linux 内核之后第二大下载的开源软件。这种积极的原因是多种多样的 - 它是开源的,相对容易建立,快速,可扩展并且有一个巨大的社区支持它。 49 | 50 | 当然,部署 Elasticsearch 集群只是第一步。由于我们正在讨论索引的大量数据集,随着时间的推移,这些数据的数量将不断增加,因此用于 SIEM 的任何 Elasticsearch 部署都需要具有极高的可扩展性和容错性。 51 | 52 | 这需要许多特定的子任务。我们已经提到使用排队机制来确保数据在丢失或数据突发时不会丢失,但是你还需要关注关键的 Elasticsearch 性能指标,如索引速率和节点 JVM 堆和 CPU。再次,你可以使用监控 API 来达到此目的。容量规划也很重要,如果你部署在云上,则自动扩展策略很可能是确保你有足够的资源进行索引所必需的。 53 | 54 | 另一个考虑是数据保留。 55 | 56 | 为了进行高效的事后取证和调查,你需要一个长期的存储策略。例如,如果你注意到源自特定 IP 的流量大幅增加,你需要比较这些历史数据以验证它是否为异常行为。一些攻击可能会在几个月内缓慢演变,并且作为分析师,拥有这些历史数据是成功检测模式和趋势的关键。 57 | 58 | 毋庸置疑,ELK Stack 不支持开箱即用的归档功能,因此你需要弄清楚自己保留数据的体系结构。理想情况下,不会在财务上削弱你的组织。 59 | 60 | 查询 61 | -------- 62 | 63 | 一旦你的数据在 Elasticsearch中 收集,分析并建立索引,下一步就是查询数据。 你可以使用 Elasticsearch REST API 来做到这一点,但很可能你会为此使用Kibana。 64 | 65 | 在[Kibana](https://logz.io/blog/kibana-tutorial/)中,使用 Lucene 语法查询数据。 例如,常见的搜索类型是字段级搜索。 例如,假设我正在查找组织中某个人执行的操作所生成的所有日志消息。 因为我在所有数据源中标准化了一个名为 _username_ 的字段,所以我可以使用这个简单的查询: 66 | 67 | `username:”Daniel Berman”` 68 | 69 | 这种查询可以使用逻辑符,比如 AND, OR, NOT 70 | 71 | `username:”Daniel Berman” AND type:login ANS status:failed` 72 | 73 | 同样,如果你想使用 ELK Stack 用于 SIEM,你将需要利用 Logstash 的分析能力来处理你的数据 - 你如何设法做到这一点会影响你轻松浏览你导入的多个数据源的查询方式。 74 | 75 | 仪表盘 76 | ---------- 77 | 78 | Kibana 以其可视化功能而闻名,支持各种不同的可视化类型,并允许用户以他们喜欢的任何方式对其数据进行切片和裁切。您可以创建饼图,图表,地图,单个度量标准,数据表等等,结果非常有效。 79 | 80 | 以下是针对AWS环境在Kibana中构建的SIEM仪表板的示例: 81 | 82 | ![仪表盘](https://logz.io/wp-content/uploads/2018/06/image1.png) 83 | 84 | 在 Kibana中 创建仪表板不是一项简单的任务,需要熟悉数据和构建日志消息的不同字段。更有甚者,Kibana 还缺少特定的功能,例如可视化中的动态链接。有[解决方法](https://logz.io/blog/kibana-hacks/),但内置功能将会让你受益良多。 85 | 86 | Kibana 也不支持安全共享对象。如果你发现安全漏洞并希望与同事共享仪表板或单个可视化文件,则 Kibana 中的共享链接不会被标记。你可以在 Kibana(X-Pack)或可以使用的开源解决方案之上实施商业附加组件。 87 | 88 | 关联 89 | ----------- 90 | 91 | SIEM 的另一个关键要素是事件关联。 正如我们在[之前的文章](https://logz.io/blog/what-is-siem/)中已经定义的那样,事件关联是将来自不同数据源的信息连接成一种模式, 表明在安全方面有问题。 相关性规则定义了形成这种模式的特定事件序列。 92 | 93 | 例如,可以创建规则以识别何时在特定时间段内从特定 IP 范围和端口发送超过x个请求量。 关联规则的另一个示例将与特权帐户的创建一起寻找异常数量的失败登录。 94 | 95 | 这些关联规则由各种 SIEM 工具提供或针对不同的攻击情景预定义。 ELK Stack 当然没有内置的关联规则,因此分析人员可以根据使用 Logstash 执行的解析和处理来使用 Kibana 查询来关联事件。 96 | 97 | 警报 98 | ------ 99 | 100 | 没有警报,关联规则就没有什么意义。 在识别可能的攻击模式时发出警报是 SIEM 系统的关键组成部分。 101 | 102 | 继续上面的例子,如果你的系统记录了来自特定 IP 范围的大量请求或异常数量的登录失败,则需要将警报发送给组织中正确的人员或团队。 速度是关键 - 通知发送得越快,缓解成功的机会就越大。 103 | 104 | ELK Stack 以其开放源代码形式,没有提供内置的警报机制。 为了增加这个功能,ELK Stack 需要增加一个警报插件或附件。 再次,X-Pack 是一种选择。 另一个选择是添加 [ElastAlert](https://github.com/Yelp/elastalert)- 一个可以添加到 Elasticsearch 之上的开源框架。 105 | 106 | 事件管理 107 | ------------------- 108 | 109 | 问题明确后,分析人员发出警报。 现在怎么办? 你的组织如何对事件做出响应将决定结果。 SIEM 系统旨在帮助安全人员的下一步 - 包含事件,必要时升级它,缓解它并扫描漏洞。 110 | 111 | ELK Stack 在帮助分析人员识别事件但对管理事件没有太多帮助时非常棒。 即使在堆栈顶部实施警报附加功能,为了有效管理事件,也需要管理触发警报的方法。 否则,可能会迷失在众多警报中并且错过重要事件。 自动化升级过程和创建票据对于有效的事件处理也很重要 112 | 113 | 总结 114 | ------------- 115 | 116 | 那么,ELK Stack 可以用于 SIEM 吗? 117 | 118 | 这个问题的答案很简单。 在其原始形式中,由 Logstash,Elasticsearch,Kibana 和 Beats 组成 - ELK Stack **不是** SIEM解决方案。 119 | 120 | 我们来总结一下上面的关键点: 121 | 122 | ![chart](https://logz.io/wp-content/uploads/2018/06/chart-1.png) 123 | 124 | 虽然这是一个非常强大的集中日志记录工具,但 ELK Stack 不能直接用于 SIEM。 缺少内置警报功能,关联规则和缓解功能 - ELK Stack 无法完成安全分析人员所需的完整工具箱。 125 | 126 | 当然,ELK Stack 可以增加其他平台和服务。 这正是市场上的几种[开源SIEM解决方案](https://logz.io/blog/open-source-siem-tools/)所做的。 但是这需要组织的巨大工程技术专长。 将 ELK Stack 与其他附加组件和平台合并所需的资源和技术知识的数量,更不用说财务成本,因此选择商业 SIEM 也成为一个不错的选择。 127 | -------------------------------------------------------------------------------- /你并不知道Node.md: -------------------------------------------------------------------------------- 1 | ## 你并不知道Node 2 | 3 | > 原文:[You don’t know Node](https://medium.com/@samerbuna/you-dont-know-node-6515a658a1ed) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 在今年 Forward.js (一个 JavaScript)会议中,我做了主题为“你并不知道 Node”的演讲。在这个演讲中,我向观众提出一些关于 Node.js 运行时的具有挑战性的问题,大多数**技术相关观众**无法回答其中的大部分问题。 12 | 13 | 我并没有进行实际的统计,但是在那个房间感觉是这个样子的。并且有一些勇敢的观众在演讲之后向我承认了这一事实。 14 | 15 | 这也就是我做此次演讲的原因。我不认为我们以正确的方式教学 Node!大多数的 Nodejs相关的教学概念集中于Node 包却不是它的运行时。大多数的包都将 Node 运行时包裹在模块中(比如 http 或者 stream)。当你遇到问题的时候,这些问题可能存在于运行时之中,如果你不知道Node 运行时的话, 你就陷入麻烦了。 16 | 17 | > 这个问题:多数的 Nodejs相关的教学概念集中于Node 包却不是它的运行时 18 | 19 | 我为这篇文章选择了一些问题并且做出回答。它们将以标题的形式在下面呈现。首先尝试在你自己心中做出回答! 20 | 21 | *如果你发现错误或者具有误导性的回答,请让我知道。* 22 | 23 | ### 问题 #1: 什么是调用栈并且它是V8的一部分么? 24 | 25 | 调用栈当然是 V8 的一部分。它是 V8 用来追踪函数调用的一种数据结构。每次我们调用一个函数的时候,V8都会将向函数调用栈中压入一个对于函数的引用,它对于其它函数的内嵌函数也会这样做。这也包括递归调用函数的函数。 26 | 27 | ![img](https://cdn-images-1.medium.com/max/800/1*9xKwtu4Gq-a7Pj_tWJ-tog.png) 28 | 29 | 当函数中的内嵌函数到达末端的时候,V8 就会每次弹出一个函数并且在它的位置使用返回值。 30 | 31 | 为什么理解 Node 是重要的?因为你在每个 Node 进程中只能获取一个调用栈。如果你让这个调用栈保持忙碌,那么你的整个 Node 进程也会是忙碌的。记住这一点。 32 | 33 | #### 问题 #2: 什么是事件循环? 它是V8的一部分吗? 34 | 35 | 你认为事件循环是在这张图的什么地方? 36 | 37 | ![img](https://cdn-images-1.medium.com/max/800/1*nLwOhFq_i4XbxRWUoXMlQQ.png)The event loop is provided by the *libuv* library. It is not part of V8. 38 | 39 | 事件循环是由 *libbuv* 库提供,它不是 V8 的一部分。 40 | 41 | 事件循环处理外部事件并且将它们转换成回调调用。它是一个从事件队列中跳去事件的循环并且将它们的回调压入到调用栈中。它也是一个多相回调。 42 | 43 | 如果这是你第一次听说事件循环,这些概念将可能不会那么有用。这个事件循环是一张更大的图的一部分。 44 | 45 | ![img](https://cdn-images-1.medium.com/max/800/1*lj3_-x3yh-114QzWpFq8Ug.png) 46 | 47 | 你需要理解这张更大的图从而理解事件循环。你需要理解 V8 的角色,知道 Node 的 API,并且知道事件如何进入队列从而被 V8 所执行。 48 | 49 | 50 | Node 的 API 就是一些函数,比如 `setTimeout` 或者 `fs.readFile`。这些并不是 JavaScript 中的一部分。它们是由 Node 提供的函数。 51 | 52 | 53 | 事件循环位于这张图(真的是一个更复杂的版本)的中间位置,就好像是一个组织者。当 V8 调用栈为空的时候,事件循环可以决定下一步执行哪一个。 54 | 55 | #### 问题 #3: 当调用栈以及事件循环都为空的时候,Node会做什么? 56 | 57 | 很简单,它会退出。 58 | 59 | 60 | 当你运行一个Node程序的时候,Node 将会自动开始事件循环并且当事件循环变为idle 的时候并且没有其它的事情需要做的时候,这个进程将会退出。 61 | 62 | 为了保持 Node进行运行,你需要在事件队列的某个地方放一些东西。比如,当你启动一个计时器或者一个 HTTP 服务的时候,你基本上就是告诉事件循环保持运行并且检查这些事件。 63 | 64 | ### 问题 #4: 除了V8以及Libuv,Node还有哪些外部依赖? 65 | 66 | 下面的是 Node 进行需要的所有的单独库: 67 | 68 | - http-parser 69 | - c-ares 70 | - OpenSSL 71 | - zlib 72 | 73 | 它们对于 Node 来说都是外部依赖。它们具有它们自己的源代码。它们具有它们自己的证书。Node 只是使用它们。 74 | 75 | 你希望记住因为你想知道你的程序在什么地方运行。如果你在处理数据压缩,你可能遇到一些 zlib 库使用的一些困难。你可能在解决一个 zlib 的 bug。不要把所有的事都怪罪于 Node。 76 | 77 | ### 问题 #5: 可以不使用V8来运行 Node? 78 | 79 | 这可能是一个棘手的问题。你需要一个 VM 来运行 Node 进程,但是 V8 并不是你唯一可以试用的 VM。你可以使用 *Chakra*。 80 | 81 | 获取 Github仓库来跟追踪 node-chakra 的进程:https://github.com/nodejs/node-chakracore 82 | 83 | ### 问题 #6: module.exports 和 exports 的区别是什么? 84 | 85 | 你可以总是试用 `module.exports` 来导出你模块的 API。你也可以`exports` 除了一种情况: 86 | 87 | ``` 88 | module.exports.g = ... // Ok 89 | exports.g = ... // Ok 90 | 91 | module.exports = ... // Ok 92 | exports = ... // Not Ok 93 | ``` 94 | 95 | *为什么?* 96 | 97 | `exports` 只是一个对于 `module.exports` 的引用或者别名。当你改变 `exports` 的时候,你是在改变那个引用而不是改变官方的 API(`module.exports`)。你将只会获得一个模块作用域内的局部变量。 98 | 99 | ### 问题 #7: 顶级变量怎么不是全局变量? 100 | 101 | 如果你有一个 `module1` 定义了一个顶级变量 `g`: 102 | 103 | ``` 104 | // module1.js 105 | var g = 42; 106 | ``` 107 | 108 | 并且你有一个 `module2` 引入了 `module1` 并且尝试访问变量 `g`,你将会发现 `g 是未定义的`。 109 | 110 | *为什么?*在浏览器中你如果做同样的操作,你能够在所有的变量在定义之后被引入就可以访问顶级变量。 111 | 112 | 每一个 Node 文件都会在背后获取它自己的立即执行函数表达式(IIFE)。所有在这个 Node 文件里面定义的变量都是在这个 IIFE 作用域内。 113 | 114 | **相关问题**:运行下面仅仅包含一行代码的 Node 文件的输出回事什么: 115 | 116 | ``` 117 | // script.js 118 | console.log(arguments); 119 | ``` 120 | 121 | 你将会看到一些参数! 122 | 123 | ![img](https://cdn-images-1.medium.com/max/800/1*mLd8sj1_SFudZNisAeiOAQ.png) 124 | 125 | *为什么?* 126 | 127 | 128 | 因为 Node 执行的是一个函数。 Node 将你的代码使用函数来包装并且这个函数准确定义了上面你看到的5个参数。 129 | 130 | ### 问题 #8: 对象`exports`,`require`和`module`都是在每个文件中全局可用,但每个文件都不同。 这是如何实现的? 131 | 132 | 133 | 当你需要使用 `require` 对象的时候,你就可以直接使用它就好像是一个全局变量。然而,如果当你在不同的两个文件中检测 `require`,你将会看到两个不同的对象。这是如何实现的? 134 | 135 | Because of that same magic IIFE: 136 | 137 | 都是因为相同的神奇的 IIFE: 138 | 139 | ![img](https://cdn-images-1.medium.com/max/800/1*W926fXZZIUf7vnvE2IOnZg.png) 140 | 141 | 正如你所见,神奇的 IIFE 将你的代码传递到5个参数之中:`exports`,`require`,`modue`,`__filename` 以及 `__dirname`。 142 | 143 | 当你在 Node 试用这5个参数的时候,它们看起来是全局的,但是事实上它们仅仅是函数的参数。 144 | 145 | ### 问题 #9: Node 中的循环模块依赖是什么? 146 | 147 | 如果你有一个 `module1` 引入 `module2` 并且同样 `module2` 也引入了 `module1`,那么将会发生什么?一个错误? 148 | 149 | ``` 150 | // module1 151 | require('./module2'); 152 | // module2 153 | require('./module1'); 154 | ``` 155 | 156 | 你将不会得到一个错误。Node 允许这种情况。 157 | 158 | 那么在 `module1` 引入 `module2` 的时候,但是因为 `module2` 需要 `module1` 并且 `module1` 尚未完成,`module1` 将会仅仅获取 `module2`的一个部分版本。 159 | 160 | 你将被警告。 161 | 162 | ### 问题 #10: 什么时候试用文件系统中的同步方法 (比如 readFileSync)是可以的? 163 | 164 | Node 中的每一个 `fs` 方法都有一个同步的版本。为什么你要使用一个同步方法而不是一个异步方法呢? 165 | 166 | 有时候试用同步方法是不错的。比如,在初始化步骤中服务器依然在加载的情况下使用同步方法。大多数情况是初始化步骤之后的所有事取决与在初始化步骤中获取的数据。在不引入回调的层级,使用同步方法是可以接受的,只要你使用同步方法是一次性的事情。 167 | 168 | 然而,如果你在一个处理程序中试用同步方法,比如 HTTP 服务器请求回调,那将会很明显 100% 报错。不要那样做。 169 | 170 | ------ 171 | 172 | 我希望你能够回答一些或者全部这些具有挑战性的问题。我将会给一些除了 Node.js 基本概念以外的文章。 173 | * https://medium.freecodecamp.org/before-you-bury-yourself-in-packages-learn-the-node-js-runtime-itself-f9031fbd8b69 174 | * https://medium.freecodecamp.org/requiring-modules-in-node-js-everything-you-need-to-know-e7fbd119be8 175 | * https://medium.freecodecamp.org/understanding-node-js-event-driven-architecture-223292fcbc2d 176 | * https://medium.freecodecamp.org/node-js-streams-everything-you-need-to-know-c9141306be93 177 | * https://medium.freecodecamp.org/node-js-child-processes-everything-you-need-to-know-e69498fe970a 178 | * https://medium.freecodecamp.org/scaling-node-js-applications-8492bd8afadc 179 | -------------------------------------------------------------------------------- /出去就餐并且理解Express.js的基础知识.md: -------------------------------------------------------------------------------- 1 | ![](https://cdn-images-1.medium.com/max/11520/1*iMkFu1T52fkSnlZDlCrvkQ.jpeg) 2 | 3 | ## 出去就餐并且理解Express.js的基础知识 4 | 5 | >原文:[Going out to eat and understanding the basics of Express.js](https://medium.freecodecamp.org/going-out-to-eat-and-understanding-the-basics-of-express-js-f034a029fb66) 6 | > 7 | >译者:[madneal](https://github.com/madneal) 8 | > 9 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 10 | > 11 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 12 | 13 | 如果你曾经去过一个坐下来就餐的餐厅,那么你可以了解 Express 的基础知识。 但是,如果你刚刚开始构建你的第一个 Node.js 后端......你可能并不会很顺利。 14 | 15 | 是的 - 如果你曾经有过 JavaScript 经验,学习 Node 肯定更容易。 但是,在构建后端时面临的挑战与在前端使用JavaScript 时所面临的挑战完全不同。 16 | 17 | 当我学习Node时,我选择了困难的方式。 我一遍又一遍地学习电子书,写作教程和视频,直到我终于明白我**为什么**要做我正在做的事情。 18 | 19 | 有一个更简单的方法。 我打算用一个餐馆的比喻来解释你的第一个应用程序的四个关键部分。 [Express.js](https://expressjs.com/) 是一个组织你的代码的流行框架,我会为任何初学者推荐它。 稍后我会进一步解释。 20 | 21 | 下面是我们将会涉及到的四个关键部分: 22 | 23 | 1. The require statements 24 | 2. Middleware 25 | 3. Routing 26 | 4. App.listen()/ Starting the server 27 | 28 | 在这个比喻中,你是一个餐馆老板,希望雇用一个总经理 - 创建所有流程并且进行管理,这样餐厅就可以顺利运行,客户也就快乐了。 29 | 30 | 下面是接下来部分的预览: 31 | 32 | ![](https://cdn-images-1.medium.com/max/2578/1*gWVqib20b1NNzB6vrM-U6w.png) 33 | 34 | 最后,你将会理解基本 Express app 的每个部分的功能。 35 | 36 | ## 步骤1: 雇佣经理 (require statements) 37 | 38 | 在这个例子中,你是餐馆老板。 而且你需要聘请专家来管理你的新餐厅的日常运作。 你当然不是专家,你不能把它交给服务员和厨房去搞清楚。 39 | 40 | 如果你想经营一家高效安全的餐厅,你需要有人来保证你的员工以最高的效率工作。 Express 就是新的经理。 41 | 42 | 第一部分非常简单。 与其他 NPM 软件包一样,你需要使用 npm 安装 express 模块,然后使用 **require** statement 来加载模块。 43 | 44 | ![](https://cdn-images-1.medium.com/max/2596/1*VjyG-yoVn9aUYJ_cdN6RYA.png) 45 | 46 | 不像其它的许多 NPM 包,你也需要使用这行: 47 | 48 | const app = express(); 49 | 这是因为你需要一个变量来保存你的新的 Express 应用程序。 Express 不是 Node 的默认部分。 50 | 51 | ## 步骤二: 在餐厅做决定 (middleware) 52 | 53 | 让我们在这停一下。餐厅里最常见的例程有哪些?我们脑海中立马出现了3个: 54 | 55 | 1. 给新顾客安排座位 56 | 2. 接受食物订单 57 | 3. 在用餐结束进行确认 58 | 59 | 对于每一个例程,都需要进行一系列的进程才能执行行动。比如,在你给顾客安排座位之前,你需要知道: 60 | 61 | 1. 他们是不是穿了衬衫和鞋子(以及裤子)?否则,他们不能被安排座位。 62 | 2. 如果他们想坐在吧台那里,他们是否已经有21岁(如果你在美国的话) 63 | 64 | 这不是海滩酒吧! 同样,在你的代码中,你需要验证请求是否具有某些标准,然后才能继续。 例如,如果有人尝试登录到你的网站: 65 | 66 | 1. 他们是否具有账户? 67 | 2. 他们是否输入了正确的密码? 68 | 69 | 这是 **middleware** 概念的来源。Middleware 功能允许你对任何传入的请求采取行动,并在发回响应之前对其进行修改。 70 | 71 | ![](https://cdn-images-1.medium.com/max/2000/0*8HIzvtX-DA3C26uv.png) 72 | 73 | 在你的餐厅,你需要一系列的规则来决定你是否应该接待来访的人。 比方说,一对夫妇走进你的餐厅。 在给他们一张桌子之前,你有一条规则:他们穿着衬衫和鞋子吗? 74 | 75 | ![](https://cdn-images-1.medium.com/max/2636/1*Gqix0p7PBNJ5htTY3sT7OQ.png) 76 | 77 | 首先,你从[app.use()](http://expressjs.com/en/api.html#app.use)开始。这意味着这些仅仅是下一个路线需要应用的规则。它们不是 GET,POST,PUT或DELETE。 78 | 79 | 在第四行,你有一个匿名函数,参数 req,res 和 next。对于这个代码块的目的,你只是检查请求(req),看它是否有衬衫和鞋子。 80 | 81 | 你最后还需要使用next()函数,因为你只是在这里验证服装。之后,在路线中,你将允许客人获得实际的桌子。 82 | 83 | 在第五行和第六行,你检查他们是否有衬衫和鞋子。 84 | 85 | 而在第7-9行中,只有两者兼而有之才行。 86 | 87 | 上面的代码块缺少一个重要的事情:一个**路径**。这是请求中包含的特定字符串。而且由于缺少路径,它将在每个请求上运行。 88 | 89 | 你可以想象?当顾客进入餐馆...点了食物...要求支票...员工将被迫在他们上下看他们确定他们穿衣服!这是一个快速停业的办法。 90 | 91 | ![](https://cdn-images-1.medium.com/max/2578/1*fjZKIJYmTIxQmVMURYTW9g.png) 92 | 93 | 所以,我们在上面的例子中改变第4行。 现在,我们只会在用户请求“/ table”路径时运行这个代码。 94 | 95 | 完整的解释: 96 | 97 | ![](https://cdn-images-1.medium.com/max/2606/1*d1OPYjAlr6mUWtjtMRbk6g.png) 98 | 99 | ## 步骤3: 执行常见的例程 (路由) 100 | 101 | 让我们继续就座的例子。 到目前为止,我们只知道如何验证某人是否应该就做。 但是我们实际上并不知道如何把他们指引到桌子旁边并且就坐。 102 | 103 | 这就是**路由**的来源。路由允许我们根据**路径**编写具体的行动。 选项是 GET,POST ,PUT 和 DELETE,但现在我们将重点介绍 GET 和 POST。 104 | 105 | 在餐厅的环境下,我们需要创建一个 GET 请求,以便选择一个特定的桌子并安排客人就做。 GET 不会修改或添加新数据到你的数据库。 他们只是检索基于特定参数的信息。 106 | 107 | 在这种情况下,假设你需要创建一个程序来安排两个派对。 2号来自客户的要求。 108 | 109 | ![](https://cdn-images-1.medium.com/max/2572/1*pGvgMABGA1xzrSL9EFGQmQ.png) 110 | 111 | 好的,在我解释之前:是的,这只是在最后发送信息。 实际上还没有找到一个具体的表格来给客户安排座位。 我需要在一个数组中搜索一个打开的表格,这涉及到更多的背景故事......这超出了本教程的范围。 112 | 113 | 在第12行中,我们定义了当宾客**请求**'table'**路由**时查找表的过程。 就像上面的中间件示例一样,我们有可用的请求和响应参数。 它也有一个**参数**,金额。 在这个例子中,这是两个。 114 | 115 | 事实上,第12行函数声明之后的所有内容在技术上都是**middleware**,因为它修改了用户请求。 你会看到图中的结尾。 116 | 117 | 在第13行中,我们从请求对象的**参数**中访问聚会中的人数。 由于请求来自用户,所以没有声明任何地方,我们没有任何前端代码。 所以如果这是一个真正的应用程序,请求可能如下所示: 118 | 119 | req = { 120 | params: { 121 | amount: 2; 122 | } 123 | } 124 | 125 | 在第13行中,我们的 party 变量访问请求中的 params 对象的 amount 属性。 126 | 127 | 最后在第14行,我们发送响应给客户:我们正在寻找合适的桌子。 128 | 129 | 这是一次很多。 下面一张图表: 130 | 131 | ![](https://cdn-images-1.medium.com/max/3666/1*k7DkIw1cheKYBwu_AC4SAA.png) 132 | 133 | ## 步骤3.5: 让你的餐厅有效率 (路由) 134 | 135 | 现在您可以追踪从请求到响应的完整路径。 但是,随着你的应用程序的规模不断扩大,你将不希望单独为每条路由编码规则。 你会发现一些路由共享相同的规则,所以你需要找到一种方法来将一组规则应用到多个路由。 136 | 137 | 就座位而言,您可以将你的客户安置在吧台或餐桌旁。 他们有衬衫和鞋子的共同规则,但是在酒吧里坐着要求每个人都超过 21岁。 138 | 139 | 而且,在服务客户方面,你需要使用稍微不同的程序来供应开胃菜,主菜和晚餐。 但是,这三条路线也有很多共同之处。 140 | 141 | 这是路由器进来的地方。路由器让你分组你的路由,这样你就可以创建通用的规则。 142 | 143 | ![](https://cdn-images-1.medium.com/max/2394/1*6Irrxz4EmHaPgVm0JRgVLg.png) 144 | 145 | 我们需要创建 middleware 来覆盖这些情况。 现在我会将考虑到上面的就座案例,对上面的代码进行重写。 146 | 147 | 这是完整的代码片段: 148 | 149 | ![](https://cdn-images-1.medium.com/max/2598/1*Pih87WdfXU_PEXkcbsaAIw.png) 150 | 151 | 我将分别讨论每个部分。 152 | 153 | 在第 4 行,我们声明我们的路由器。 154 | 155 | 在第6行和第14行,我们现在使用seatingRouter.use()来代替app.use()来表示这个中间件只与seatRouter路由有关。 156 | 157 | 最后,在第21行中,我们添加了更多的中间件,以显示每个座位路由器以“/ seating”开头。 所以,如果有人要求在酒吧坐一个座位,完整的路径是'/ seating / bar',这可能会有点不合理,因为当你在第4行创建路由器时,你可能会预期路径被定义。 这很正常! 158 | 159 | 这里是以图表的形式: 160 | 161 | ![](https://cdn-images-1.medium.com/max/2000/1*-1x9T6VvBCQihyzwqgnGIA.png) 162 | 163 | 并且当你添加一个 GET 路由的时候, 它将会转到你上面分配的路由。 164 | 165 | ![](https://cdn-images-1.medium.com/max/2604/1*EPEUF9z94mMlCYXMB6HENA.png) 166 | 167 | ## 步骤4: 开放营业 (端口) 168 | 169 | 好吧,最后一部分。 到目前为止,你已经雇佣了一位经理,在接受客户请求之前定义了要做的事情,并且确定如何处理特定的客户请求。现在,你只需确定所需位置的地址即可。 170 | 171 | 你的服务器端口有点像餐厅本身的地址。 由于你的服务器可以同时处理多种类型的餐厅(或服务器端脚本),因此你需要告知每个脚本应在哪里运行。 172 | 173 | ![](https://cdn-images-1.medium.com/max/2650/1*xGoTkrNMLnwyh7zR2wbbVA.png) 174 | 175 | 在上面的例子中,端口是 3000,它位于你的计算机上。 所以如果你输入: 176 | 177 | ​ `https://localhost:3000/` 178 | 179 | 在你的浏览器中,并且你在运行你的 Node 应用程序,服务器知道运行特定的脚本。 在这种情况下,只要输入URL,您将在控制台中记录消息,并能够使用任何路由。 如果餐厅本身是您的电子商务应用程序,那么它现在在地址 3000 处开始营业。 180 | 181 | ![](https://cdn-images-1.medium.com/max/2650/1*kl9doAbsvsaQNJdFWhc2-Q.png) 182 | 183 | 你喜欢这个教程吗? 给它点赞,让别人也可以发现它。 184 | -------------------------------------------------------------------------------- /正则表达式入门.md: -------------------------------------------------------------------------------- 1 | # 正则表达式入门 — 一个通过例子来说明的备忘单 2 | 3 | > 原文:[Regex tutorial — A quick cheatsheet by examples](https://medium.com/factory-mind/regex-tutorial-a-simple-cheatsheet-by-examples-649dc1c3f285) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![](https://cdn-images-1.medium.com/max/2560/0*qASU92GfMj2HCTMg.jpg) 12 | 13 | 正则表达式(regex 或 regexp)在通过搜索特定搜索模式的一个或多个匹配(即 ASCII 或 unicode 字符的特定序列)**从任何文本中提取信息时**非常有用。 14 | 15 | 应用领域从验证到解析/替换字符串,将数据转换为其他格式以及网络爬虫。 16 | 17 | 最有趣的功能之一是,一旦你学会了语法,你就可以在(几乎)所有编程语言中使用这个工具(JavaScript,Java,VB,C#,C / C ++,Python,Perl,Ruby,Delphi,R,Tcl 等等),对引擎支持的最高级功能和语法版本的支持有一点区别)。 18 | 19 | 让我们首先看一些例子和解释。 20 | 21 | ## 基本知识点 22 | 23 | ### 锚 — ^ 以及 $ 24 | 25 | The 匹配任意字符串以 The 为开头-> [试一下!](https://regex101.com/r/cO8lqs/2) 26 | 27 | end$ 匹配任意字符串以 end 为结尾 28 | 29 | ^The end$ 匹配字符串的(开头和结尾分别是 The end) 30 | 31 | roar 匹配任意具有 roar 的字符串 32 | 33 | ### 量词 — * + ? 以及 {} 34 | 35 | abc* 匹配一个字符串具有 ab 其后有0个或者多个 c->[试一下!](https://regex101.com/r/cO8lqs/1) 36 | 37 | abc+ 匹配一个字符串具有 ab 其后有1个或者多个 c 38 | 39 | abc? 匹配一个字符串具有 ab 其后有0个或者1个 c 40 | 41 | abc{2} 匹配一个字符串具有 ab 其后有2个 c 42 | 43 | abc{2,} 匹配一个字符串具有 ab 其后有2个或者多个 c 44 | 45 | abc{2,5} 匹配一个字符串具有 ab 其后有2到5个 c 46 | 47 | a(bc)* 匹配一个字符串具有 a 其后有0到多个 bc 的副本 48 | 49 | a(bc){2,5} 匹配一个字符串具有 a 其后有2到5个 bc 的副本 50 | 51 | ### OR 操作符 — | 或 [] 52 | 53 | a(b|c) 匹配一个字符串具有 a 其后有 b 或者 c -> [试一下!](https://regex101.com/r/cO8lqs/3) 54 | 55 | a[bc] 与上一条相同 56 | 57 | ### 字符类 — \d \w \s 以及 . 58 | 59 | \d 匹配一个数字字符-> [试一下!](https://regex101.com/r/cO8lqs/4) 60 | 61 | \w 匹配一个单词字符(字母以及下划线) -> [试一下!](https://regex101.com/r/cO8lqs/4) 62 | 63 | \s 匹配空白字符(包括 tab 以及换行) 64 | 65 | . 匹配任意字符->[试一下!](https://regex101.com/r/cO8lqs/5) 66 | 67 | 仔细使用 . 操作符,因为类或者否定类字符(我们在下面会提到)将会更快更准确。 68 | 69 | `\d`, `\w` 以及 `\s` 分别对应其否定类 `\D`, `\W` 以及 `\S` 。 70 | 71 | 例如, `\D` 将执行与 `\d` 获得的相反的匹配。 72 | 73 | \D 匹配一个非数字字符->[试一下!](https://regex101.com/r/cO8lqs/6) 74 | 75 | 为了获取字面上疑似的字符,你必须使用反斜杠 `\` 来转义字符 `^.[$()|*+?{\`,因为它们具有特殊含义。 76 | 77 | \$\d* 匹配一个字符具有一个数字字符其前面是一个 $>[试一下!](https://regex101.com/r/cO8lqs/9) 78 | 79 | 80 | 注意你也可以匹配**非打印字符**比如 tabs `\t`,换行 `\n`,回车 `\r`。 81 | 82 | ### 标志 83 | 84 | 我们正在学习如何构建一个正则表达式但是却忘记了一个基础的概念:**标志**。 85 | 86 | 一个正则表达式的格式通常是这个样子的 `/abc/`,搜索模式通过两个斜杠符 `/` 进行区分。在末尾我们可以规定一个标志使用以下的值(我们也可以将它们相互结合): 87 | 88 | * **g**(全局的) 在第一匹配之后不会立即返回,从前面匹配之后继续搜索 89 | 90 | * **m** (多行的) 当使用 `^` 以及 `$` 的时候将会匹配行首和行尾而不是整个字符串 91 | 92 | * **i** (大小写不敏感的) 让整个表达式大小写不敏感(比如 `/aBc/i` 将匹配 `Abc`) 93 | 94 | ## 中级知识点 95 | 96 | ### 分组以及捕获 — () 97 | 98 | a(bc) 括号产生一个值为 bc 的捕获分组-> [试一下!](https://regex101.com/r/cO8lqs/11) 99 | 100 | a(?:bc)* 我么可以使用 ?: 让捕获分组不起作用->[试一下!](https://regex101.com/r/cO8lqs/12) 101 | 102 | a(?bc) 我们可以使用 ? 将名字放在分组中 -> [试一下!](https://regex101.com/r/cO8lqs/17) 103 | 104 | 当我们需要使用你首选的编程语言从字符串或数据中提取信息时,此运算符非常有用。 由几个组捕获的任何多次出现都将以经典数组的形式公开:我们将使用匹配结果的索引来访问它们的值。 105 | 106 | 如果我们选择为组添加名称(使用(`?` ...)),我们将能够使用匹配结果检索组值,如字典,其中字典的名称就是刚才添加的名称。 107 | 108 | ### 方括号表达式 — [] 109 | 110 | [abc] 匹配一个具有 要么一个 a 或者一个 b 或者一个 c 的字符串-> 等同于 `a|b|c`-> [试一下!](https://regex101.com/r/cO8lqs/7) 111 | 112 | [a-c] 与前一条相同 113 | 114 | [a-fA-F0-9] 字符串代表一个十六进制数,大小写不敏感-> [试一下!](https://regex101.com/r/cO8lqs/22) 115 | 116 | [0-9]% 一个具有从0到9其后后一个 % 符号 117 | 118 | [^a-zA-Z] 一个不是大小写字母的字符串。在这种情况下,^ 被用为 表达式的否定。->[试一下!](https://regex101.com/r/cO8lqs/10) 119 | 120 | 请记住,在括号内表达式中,所有特殊字符(包括反斜杠\)都会失去它们的特殊功能:因此我们不会应用“转义规则”。 121 | 122 | ### 贪婪和惰性匹配 123 | 124 | 量词 ( `* + {}`) 是贪婪操作符, 所以他们尽可能地通过提供的文本扩展匹配. 125 | 126 | 比如, `<.+>` 会从 `This is a **
simple div
** test` 中匹配 `
simple div
`。 为了仅仅匹配 div 标签, 我们可以使用一个 `?` 让它变为惰性: 127 | 128 | <.+?> 匹配 任意字符被包含在 < 以及 >之中,出现一到多次, 需要的时候才会扩展-> [试一下!](https://regex101.com/r/cO8lqs/24) 129 | 130 | 注意更好的解决方案是避免使用 `.`来构建一个更严格的正则表达式: 131 | <[^<>]+> 匹配任意的字符除了 `<` 或者 `>` 一次或者多次被包含在 < 以及 > 之中-> [试一下!](https://regex101.com/r/cO8lqs/23) 132 | 133 | ## 高级知识点 134 | 135 | ### **边界 — \b 以及 \B** 136 | 137 | \babc\b 执行“仅限整个单词”搜索->[试一下!](https://regex101.com/r/cO8lqs/25) 138 | 139 | `\b` 代表一个锚类似于符号 (等同于 `$` 以及 `^`) 的匹配位置, 其中一侧是单词字符(如 `\w`),另外一侧不是单词字符(例如它可能是字符串的开头或空格字符)。 140 | 141 | 142 | 随之而来是它的否定, `\B`. 这将会匹配所有 `\b` 不会匹配的位置如果我们希望搜索模式可以被单词字符所匹配。 143 | 144 | \Babc\B 仅在搜索模式被单词字符包围的时候才会匹配 -> [试一下!](https://regex101.com/r/cO8lqs/26) 145 | 146 | ### 返回引用— \1 147 | 148 | ([abc])\1 使用 `\1` 将会匹配与第一个捕获分组相同的文本 -> [试一下!](https://regex101.com/r/cO8lqs/14) 149 | 150 | ([abc])([de])\2\1 我们可以使用 \2 (\3, \4, 等等)来获取被第二个(第三个, 第四个, 等等.)捕获分组相同的文本 -> [试一下!](https://regex101.com/r/cO8lqs/15) 151 | 152 | (?[abc])\k 我们将分组名称命名为`foo` 并随后使用 `(\k)` 来进行引用。结果与第一个正则表达式相同 -> [试一下!](https://regex101.com/r/cO8lqs/16) 153 | 154 | ### 前瞻和后瞻 — **(?=)** 以及 **(?<=)** 155 | 156 | d(?=r) 匹配一个 `d` 并且其后有一个 `r`, 但是 `r` 将不会是整个正则表达式匹配的一部分-> [试一下!](https://regex101.com/r/cO8lqs/18) 157 | 158 | (?<=r)d 匹配一个 `d` 并且前面有一个 `r`, 但是 `r` 将不会是整个正则表达式匹配的一部分-> [试一下!](https://regex101.com/r/cO8lqs/19) 159 | 160 | 我们也可以使用否定符号 ! 161 | 162 | d(?!r) 匹配一个 `d` 并且其后不是一个 `r`, 但是 `r` 将不会是整个正则表达式匹配的一部分-> [试一下!](https://regex101.com/r/cO8lqs/20) 163 | 164 | (? [试一下!](https://regex101.com/r/cO8lqs/21) 165 | 166 | ## 总结 167 | 168 | 正如你所见,正则表达式的应用程序字段可以是多个,我确信你已经认识到在开发人员职业生涯中看到的这些任务中的至少一个,这里有一个快速列表: 169 | 170 | * 数据验证 (比如检查一个时间字符串 i 的格式是正确的) 171 | 172 | * 数据抓取(特别是网页抓取,最终按特定顺序查找包含特定单词集的所有页面) 173 | 174 | * 数据转换(将数据从“原始”转换为另一种格式) 175 | 176 | * 字符串解析(例如捕获所有URL GET参数,捕获一组括号内的文本) 177 | 178 | * 字符串替换(即使在使用通用 IDE 的代码会话期间,例如在相应的 JSON 对象中转换 Java 或 C# 类 - 将“;”替换为“,”将其设为小写,避免类型声明等) 179 | 180 | * 语法高亮,文件重命名,数据包嗅探和涉及字符串的许多其他应用程序(其中数据不必是文本) 181 | 182 | 玩得开心,如果你喜欢它,别忘了推荐这篇文章 💚 183 | 184 | **很快我将发布一篇包含常见正则表达式列表的新文章,请继续关注!** 185 | -------------------------------------------------------------------------------- /circleci-incident.md: -------------------------------------------------------------------------------- 1 | # CircleCI 20230104 安全事件报告 2 | 3 | >原文:[CircleCI incident report for January 4, 2023 security incident](https://circleci.com/blog/jan-4-2023-incident-report/) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | [2023 年 1 月 4 日,我们提醒客户](https://circleci.com/blog/january-4-2023-security-alert/) 一起安全事件。 今天,我们想与您分享发生的事情、我们学到的知识以及我们未来不断改善安全态势的计划。 12 | 13 | 我们要感谢我们的客户对于重置密钥的关注,并对此次事件可能对您的工作造成的任何干扰表示歉意。我们鼓励尚未采取行动的客户采取行动,以防止未经授权访问第三方系统和存储。此外,我们要感谢我们的客户和社区在我们进行彻底调查期间的耐心等待。为了实现负责任的披露,我们已尽最大努力在共享信息的速度与保持调查的完整性之间取得平衡。 14 | 15 | **本报告包含:** 16 | 17 | * 发生了什么? 18 | * 我们怎么知道这个攻击向量已经关闭并且可以安全构建? 19 | * 与客户的沟通和支持 20 | * 如何判断我是否受影响? 21 | * 可能有助于您的团队进行内部调查的详细信息 22 | * 我们从这次事件中学到了什么以及我们下一步将做什么 23 | * 关于员工责任与系统保障措施的说明 24 | * 安全最佳实践 25 | * 结语 26 | 27 | ## 发生了什么? 28 | 29 | *除非另有说明,否则所有日期和时间均以 UTC 报告。* 30 | 31 | 2022 年 12 月 29 日,我们的一位客户提醒我们注意可疑的 GitHub OAuth 活动。此通知启动了 CircleCI 的安全团队与 GitHub 的更深入审查。 32 | 33 | 2022 年 12 月 30 日,我们了解到该客户的 GitHub OAuth 令牌已被未经授权的第三方泄露。尽管该客户能够迅速解决问题,但出于谨慎考虑,我们在 2022 年 12 月 31 日代表客户主动启动了更换所有 GitHub OAuth 令牌的流程。尽管与 GitHub 合作提高 API 速率限制,但轮换过程需要时间 虽然目前尚不清楚其他客户是否受到影响,但我们继续扩大分析范围。 34 | 35 | 到 2023 年 1 月 4 日,我们的内部调查已经确定了未经授权的第三方入侵的范围和攻击的进入路径。迄今为止,我们了解到未经授权的第三方利用部署到 CircleCI 工程师笔记本电脑上的恶意软件来窃取有效的、支持 2FA 的 SSO session。这台机器于 2022 年 12 月 16 日遭到入侵。我们的防病毒软件未检测到该恶意软件。我们的调查表明,该恶意软件能够执行 session cookie 盗窃,使他们能够在远程位置冒充目标员工,然后升级为对我们生产系统子集的访问。 36 | 37 | 由于目标员工有权生成生产访问令牌作为员工日常职责的一部分,因此未经授权的第三方能够从数据库和存储的子集访问和泄露数据,包括客户环境变量、令牌和密钥。我们有理由相信,未经授权的第三方在 2022 年 12 月 19 日进行了侦察活动。2022 年 12 月 22 日 发生了泄露事件,这是我们生产系统中最后一次未经授权活动的记录。尽管所有泄露的数据都是静态加密的,但第三方从正在运行的进程中提取了加密密钥,使他们能够访问加密数据。 38 | 39 | 虽然我们对内部调查的结果充满信心,但我们已聘请第三方网络安全专家协助我们进行调查并验证我们的调查结果。我们迄今为止的发现基于对我们的身份验证、网络和监控工具的分析,以及我们合作伙伴提供的系统日志和日志分析。 40 | 41 | 针对这一事件,我们采取了以下行动: 42 | 43 | * 2023 年 1 月 4 日 16:35 UTC,我们关闭了帐户被盗员工的所有访问权限。 44 | * 2023 年 1 月 4 日 28:30 UTC,我们关闭了几乎所有员工的生产访问权限,限制了极少数群体的访问权限以解决运营问题。在此调查期间,我们从未有任何证据表明任何其他员工或他们的设备的凭证已被泄露,但我们采取此行动是为了限制潜在的攻击面。 45 | * 2023 年 1 月 4 日 22:30 UTC,我们修改了了所有可能暴露的生产主机,以确保安全的生产机器。 46 | * 2023 年 1 月 5 日 03:26 UTC,我们撤销了所有项目 API 令牌。 47 | * 2023 年 1 月 6 日 05:00 UTC,我们撤销了在 2023 年 1 月 5 日 00:00 UTC 之前创建的所有个人 API 令牌。 48 | * 2023 年 1 月 6 日 06:40 UTC,我们开始与 Atlassian 的合作伙伴合作,代表我们的客户轮换所有 Bitbucket token。这项工作于 2023 年 1 月 6 日 10:15 UTC 完成。 49 | * 2023 年 1 月 7 日 07:30 UTC,我们完成了 GitHub OAuth 令牌的修改,该修改是我们于 2022 年 12 月 31 日 04:00 UTC 开始的。 50 | * 2023 年 1 月 7 日 18:30 UTC,我们开始与 AWS 的合作伙伴合作,通知客户可能受影响的 AWS token。据我们了解,这些通知已于 2023 年 1 月 12 日 00:00 UTC 时完成。 51 | 52 | 在此期间,我们在外部调查人员的支持下继续进行取证调查,在我们的平台上推出额外的安全层,并构建和分发额外的工具(更多详情见下文)以支持我们的客户保护他们的 secrets。 53 | 54 | ## 我们怎么知道这个攻击向量已经关闭并且可以安全构建? 55 | 56 | 我们相信客户可以安全地在 CircleCI 上构建。 57 | 58 | 自从意识到这种攻击以来,我们采取了许多措施,既关闭了攻击向量,又增加了额外的安全层,包括: 59 | 60 | * 通过我们的 MDM 和 A/V 解决方案添加了针对此次攻击中使用的恶意软件表现出的特定行为的检测和阻止。 61 | * 由于我们实施了额外的安全措施,因此仅限极少数员工访问生产环境 我们对我们平台的安全性充满信心,并且没有迹象表明任何其他员工的设备遭到入侵。 62 | * 对于保留生产访问权限的员工,我们添加了额外的升级身份验证步骤和控制。 这将帮助我们防止可能的未经授权的生产访问,即使在 2FA 支持的 SSO session 被盗的情况下也是如此。 63 | * 跨多个触发器并通过各种第三方供应商对我们在此场景中确定的特定行为模式实施监控和警报。 64 | 65 | 我们知道安全工作永远不会结束。除了关闭这个特定的向量,我们还进行了增强和持续的审查,以确保加强对潜在攻击的防御。 66 | 67 | ## 与客户的沟通和支持 68 | 69 | 在 2023 年 1 月 4 日 22:30 UTC 完成所有生产主机的轮换后,我们确信我们已经消除了攻击向量和破坏主机的可能性。 70 | 71 | 2023 年 1 月 5 日 02:30 UTC,我们发送了披露电子邮件,[在我们的博客上发布了安全通知](https://circleci.com/blog/january-4-2023-security-alert/),通过我们的社交媒体帐户和我们的讨论论坛通知客户,并创建了一篇关于如何执行建议的安全步骤的支持文章。 72 | 73 | 我们建议所有客户更改他们的 secrets,包括 OAuth 令牌、项目 API 令牌、SSH 密钥等(有关更多详细信息,请参阅博客文章或讨论文章)。 74 | 75 | 此披露启动了与我们客户的积极和持续的沟通期。我们要感谢我们的客户对这一事件的一致响应,以及帮助我们找到机会为您提供额外的工具。我们接受了这些反馈,并作为回应构建并发布了新工具并修改了我们现有的工具,以通过以下方式为客户加快修复速度: 76 | 77 | * [秘密发现脚本](https://github.com/CircleCI-Public/CircleCI-Env-Inspector) 以创建可操作的秘密轮换列表。 78 | * CircleCI API 的两个关键变化: 79 | * 返回结帐密钥的 SHA-256 签名的新功能,以便更好地匹配 GitHub UI。 80 | * `updated_at` 字段已添加到 Contexts API 中,以便客户可以验证这些变量是否已成功轮换。 81 | * 免费和付费计划的所有客户都可以访问审计日志,以帮助客户审查 CircleCI 平台活动。 82 | 83 | 我们感谢客户就我们可以改进沟通的地方提供的所有反馈,包括让事件在我们的渠道中更加明显的机会。 84 | 85 | ## 我怎么知道我是否受到了影响? 86 | 87 | ### 我的数据有风险吗? 88 | 89 | 在此事件中,未经授权的行为者于 2022 年 12 月 22 日窃取了客户信息,其中包括第三方系统的环境变量、密钥和令牌。如果您在此期间将机密信息存储在我们的平台上,请假设它们已被访问并采取建议的缓解措施。我们建议您从 2022 年 12 月 16 日开始调查系统中的可疑活动,并在我们于 2023 年 1 月 4 日披露后完成机密修改之日结束。2023 年 1 月 5 日之后进入系统的任何内容都可以被认为是安全的。 90 | 91 | ### 是否有未经授权的行为者使用该数据访问我的任何系统? 92 | 93 | 由于此事件涉及第三方系统的密钥和令牌外泄,我们无法知道您的 secret 是否被用于未经授权访问这些第三方系统。 我们在下面提供了一些详细信息,以帮助客户进行调查。 94 | 95 | **在发布时,只有不到 5 位客户通知我们由于此事件而未经授权访问第三方系统。** 96 | 97 | ## 可能有助于您的团队进行内部调查的详细信息 98 | 99 | 在第三方取证调查员的帮助下,我们最近确认了可能有助于客户进行审计和调查的更多详细信息。 100 | 101 | ### 影响日期: 102 | 103 | * 我们在 2022 年 12 月 19 日看到未经授权的第三方访问,数据泄露发生在 2022 年 12 月 22 日。 104 | * 我们没有证据表明 2022 年 12 月 19 日之前有影响客户的活动。出于谨慎考虑,我们建议您调查从 2022 年 12 月 16 日事件开始到 1 月之后修改 secret 之间的这段时间系统中存在异常活动。 105 | 106 | ### 识别为被威胁行为者使用的 IP 地址: 107 | 108 | * 178.249.214.10 109 | * 89.36.78.75 110 | * 89.36.78.109 111 | * 89.36.78.135 112 | * 178.249.214.25 113 | * 72.18.132.58 114 | * 188.68.229.52 115 | * 111.90.149.55 116 | 117 | ### Data centers and VPN providers identified as being used by the threat actor: 118 | 119 | ### 数据中心和 VPN 提供商被识别为被威胁行为者使用: 120 | 121 | * Datacamp Limited 122 | * Globalaxs Quebec Noc 123 | * Handy Networks, LLC 124 | * Mullvad VPN 125 | 126 | ### Malicious files to search for and remove: 127 | 128 | ### 搜索和删除的恶意文件: 129 | 130 | * /private/tmp/.svx856.log 131 | * /private/tmp/.ptslog 132 | * PTX-Player.dmg (SHA256: 8913e38592228adc067d82f66c150d87004ec946e579d4a00c53b61444ff35bf) 133 | * PTX.app 134 | 135 | ### 拦截以下域名 136 | 137 | * potrax[.]com 138 | 139 | ### 查看 GitHub 审核日志文件以查找意外命令,例如: 140 | 141 | * repo.download_zip 142 | 143 | ## 我们从这次事件中学到了什么以及我们接下来要做什么 144 | 145 | **我们了解到:虽然我们有适当的工具来阻止和检测攻击,但总有机会加强我们的安全态势。** 146 | 147 | 我们拥有的身份验证、安全和跟踪工具使我们能够全面诊断和修复问题。随着恶意攻击者越来越复杂,我们正在不断改进我们的安全标准并推动最佳实践以保持领先于未来的威胁。我们将越来越积极地使用安全工具。展望未来,为了支持更保守的立场并防止攻击者不当访问我们的系统,我们将优化现有工具的配置以创建额外的防御层。 148 | 149 | ### 我们的计划: 150 | 151 | 首先,我们将为所有客户启动定期自动 OAuth 令牌轮换。 我们的计划还包括从 OAuth 到 GitHub 应用程序的转变,使我们能够在令牌中实施更精细的权限。我们还计划完成对我们所有工具配置的全面分析,包括第三方审查。我们将继续采取其他措施,包括扩大告警范围、减少会话信任、添加额外的身份验证因素以及执行更定期的访问轮换。最后,我们将使我们的系统权限更加短暂,严格限制从类似事件中获得的任何令牌的目标值。 152 | 153 | ### 我们学习到:我们可以让客户更轻松地采用我们最先进的安全功能。 154 | 155 | 通过 CircleCI 的发展,我们不断引入功能来提高客户构建管道的安全性。虽然客户可以使用高级安全功能,但我们可以做更多工作来提高这些功能的采用率。 156 | 157 | ### 我们的计划: 158 | 159 | 客户必须更容易无缝地采用可用的最新和最先进的安全功能,包括 OIDC 和 IP 范围。我们还在探索其他主动步骤,例如,自动令牌过期和未使用 secret 的通知。我们将使我们的客户更简单、更方便地创建和维护高度安全的管道,在智能管理风险的同时实现云的每一个优势。 160 | 161 | ## 关于员工责任与系统保障措施的说明 162 | 163 | 我们想说清楚。虽然一名员工的笔记本电脑通过这种复杂的攻击被利用,但安全事件是系统故障。作为一个组织,我们的责任是建立多层防护措施来抵御所有攻击向量。 164 | 165 | ## 安全最佳实践 166 | 167 | 鉴于成熟和有动机的攻击者越来越多,我们致力于与我们的客户分享最佳实践,以加强我们对未来不可避免的尝试的集体防御。以下是客户可以用来提高管道安全性的建议: 168 | 169 | * 尽可能使用 [OIDC 令牌](https://circleci.com/docs/openid-connect-tokens/) 以避免在 CircleCI 中存储长期存在的凭据。 170 | * 利用 [IP 范围](https://circleci.com/docs/ip-ranges/) 将您系统的入站连接限制为仅已知 IP 地址。 171 | * 使用 [Contexts](https://circleci.com/docs/contexts/) 合并共享机密并将对机密的访问限制为特定项目,然后可以[通过 API 自动轮换](https://circleci.com /docs/contexts/#rotating-environment-variables)。 172 | * 对于特权访问和其他控制,您可以选择使用 [runners](https://circleci.com/docs/runner-overview/#circleci-runner-use-cases),它允许您将 CircleCI 平台连接到 您自己的计算和环境,包括 IP 限制和 IAM 管理。 173 | 174 | ## 结语 175 | 176 | 我们知道没有合适的时间来响应关键系统上的安全事件,我们要衷心感谢所有在事件发生后立即采取行动的客户。正是通过这种集体行动,我们将能够更有力地应对未来的威胁。我们还亲眼目睹了我们客户社区的力量和慷慨,你们中的许多人前往我们的讨论论坛分享知识并互相帮助。感谢您在我们努力解决此事件时的支持和耐心。 -------------------------------------------------------------------------------- /Javascript中Async-Await优于Promise的6个原因.md: -------------------------------------------------------------------------------- 1 | # JavaScript中Async/Await优于Promise的6个原因 (教学) 2 | 3 | > 原文:[6 Reasons Why JavaScript’s Async/Await Blows Promises Away (Tutorial)](https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 你可能期待已久,Node 从7.6版本就是开始支持 async/await 了。如果你还到现在还没有尝试,下面是一些你应该立刻采用它的带有例子的理由,而且你永远都不想再回来了。 12 | 13 | ### Async/await 101 14 | 15 | 对于从来没有听过这个话题的人,下面将会是一个简短的介绍: 16 | 17 | * async/await 是一种写异步代码的新方式。之前对于异步代码的选择包括回调和 promise。 18 | * async/await 事实上是建立在promise之上的。它不能仅仅通过回调或者节点回调来使用。 19 | * async/wait 和 promise类似,是非阻塞的。 20 | * async/await 让异步代码看起来非常像同步代码。这就是它的能力所在。 21 | 22 | ### 语法 23 | 24 | 假设函数`getJSON`返回一个 promise,并且这个 promise 解析了一些 JSON 对象。我们只想调用它并且显示出 JSON,接着返回`"done"`。 25 | 26 | 下面是使用promise来实现 27 | 28 | ```javascript 29 | const makeRequest = () => 30 | getJSON() 31 | .then(data => { 32 | console.log(data); 33 | return "done" 34 | }) 35 | makeRequest() 36 | ``` 37 | 38 | 接着看看使用async/awiat应该是什么样子的 39 | 40 | ```javascript 41 | const makeRequest = async() => { 42 | console.log(await getJSON()) 43 | return "done" 44 | } 45 | makeRequest() 46 | ``` 47 | 48 | 在这主要有几点不同 49 | 50 | 1. 我们的函数名之前有一个关键字`async`。`await`这个关键字只能在使用`async`定义的函数里面使用。任何`async`函数都会默认返回promise,并且这个promise解析的值都将会是这个函数的返回值(在我们这个例子里面是字符串`"done"`) 51 | 2. 上面也指出了我们不能在我们代码的最高层级使用await,因为它不是在`async`函数之内的。 52 | 53 | ```javascript 54 | // 这将不会在最高层次工作 55 | // await makeRequest() 56 | 57 | // 这将会工作 58 | makeRequest().then((result) => { 59 | // 做一些事 60 | }) 61 | ``` 62 | 63 | 3. `await getJSON()`意味着`console.log`只有等到`getJSON`promise解析完毕之后才会被调用然后打印值。 64 | 65 | ### 为什么它更好? 66 | 67 | #### 1.简洁干净 68 | 69 | 看看我们要少写多少代码!即使在上述设计的例子中,很明显我们节省了一定数量的代码。我们不需要再写`.then`,创建匿名函数来处理响应,或者将变量命名为`data`,我们并不需要使用它。我们也可以避免嵌套我们的代码。这些小优点很快就累加在一起,在下面的代码例子中将会更加明显。 70 | 71 | #### 2.错误处理 72 | 73 | Async/await能够在同样的构造函数下处理同步和异步错误,在`try.catch`也可以正常运行。在下面使用promise的例子中,`try/catch`将不会处理如果`JSON.parse`失败的话,因为这是在promise内部发生的。我们需要调用在promise上调用`.catch`并且再一次写一个错误处理代码,这将比你希望中在生产环境中使用`console.log`更复杂。 74 | 75 | ```javascript 76 | const makeRequest = () => { 77 | try { 78 | getJSON() 79 | .then(result => { 80 | // 这个解析可能会失败 81 | const data = JSON.parse(result) 82 | console.log(data) 83 | }) 84 | // 取消下面的注释来处理异步错误 85 | // .catch((err) => { 86 | // console.log(err) 87 | //}) 88 | } catch (err) { 89 | console.log(err) 90 | } 91 | } 92 | ``` 93 | 94 | 现在我们在async/await中看一下相同的代码。`catch`作用域现在可以处理错误 95 | 96 | ```javascript 97 | const makeRequest = async() => { 98 | try { 99 | // 这个解析可能会失败 100 | const data = JSON.parse(await getJSON()) 101 | console.log(data) 102 | } catch (err) { 103 | console.log(err) 104 | } 105 | } 106 | ``` 107 | 108 | #### 3.条件 109 | 110 | 考虑以下的代码,假如我们需要获取一些数据并且是否返回它或者基于这个数据获取更多的值。 111 | 112 | ```javascript 113 | const makeRequest = () => { 114 | return getJSON() 115 | .then(data => { 116 | if (data.needAnotherRequest) { 117 | return makeAnotherRequest(data) 118 | .then(moreData => { 119 | console.log(moreData) 120 | return moreData 121 | }) 122 | } else { 123 | console.log(data) 124 | return data 125 | } 126 | }) 127 | } 128 | ``` 129 | 130 | 上述的代码肯定让你很头痛。很容易在层层包裹的代码中迷失自我(6层),大括号,返回语句只有在将最终结果传播到promise中才是需要的。 131 | 132 | 下面的例子通过使用async/await来进行重写,从而让代码更容易阅读。 133 | 134 | ```javascript 135 | const makeRequest = async() => { 136 | const data = await getJSON() 137 | if (data.needAnotherRequest) { 138 | const moreData = await makeAnotherRequest(data) 139 | console.log(moreData) 140 | return moreData 141 | } else { 142 | console.log(data) 143 | return data 144 | } 145 | } 146 | ``` 147 | 148 | #### 4.中间值 149 | 150 | 你可能会发现这样的情形,当你调用`promise1`之后,使用它的返回来继续调用`promise2`,接着使用这两个promise的返回结果来调用`promise3`。你的代码很有可能是这个样子的 151 | 152 | ```javascript 153 | const makeRequest = () => { 154 | return promise1() 155 | .then(value1 => { 156 | // 做一些事 157 | return promise2(value1) 158 | .then(value2 => { 159 | // 做一些事 160 | return promise3(value1, value2) 161 | }) 162 | }) 163 | } 164 | ``` 165 | 166 | 如果`promise3`不需要`value1`的话,那么可以将promise的嵌套展平一点。如果你是那种没有办法忍受这种的人,你可以将value1以及value2包裹在`Promise.all`里面来避免更深层次的嵌套,如下 167 | 168 | ```javascript 169 | const makeRequest = () => { 170 | return promise1() 171 | .then(value1 => { 172 | // 做一些事 173 | return Promise.all([value1, promise2(value1)]) 174 | }) 175 | .then([value1, value2]) => { 176 | // 做一些事 177 | return promise3(value1, value2) 178 | } 179 | } 180 | ``` 181 | 182 | 这段代码为了可读性牺牲了语义性。没有理由将value1和value2放在一个数组里面,除非是为了避免嵌套promise。 183 | 184 | 同样的逻辑在async/await中将会十分的简单直白。它可以在promise变得可怕之前让你知道你可能完成所有的事情。 185 | 186 | ```javascript 187 | const makeRequest = async() => { 188 | const value1 = await promise1() 189 | const value2 = await promise2() 190 | return promise3(value1, value2) 191 | } 192 | ``` 193 | 194 | #### 5.错误堆栈 195 | 196 | 想象以下一段代码链式调用多个promise,并且在链的的某个环节错误被抛出。 197 | 198 | ```javascript 199 | const makeRequest = () => { 200 | return callAPromise() 201 | .then(() => callApromise()) 202 | .then(() => callApromise()) 203 | .then(() => callApromise()) 204 | .then(() => callApromise()) 205 | .then(() => { 206 | throw new Error("oops") 207 | }) 208 | } 209 | 210 | makeRequest() 211 | .catch(err => { 212 | console.log(err) 213 | // 输出 214 | // Error: oops at callAPromise.then.then.then.then.then (index.js:8:13) 215 | }) 216 | ``` 217 | 218 | 这个错误对谈返回了一个promise链,对于错误发生的地方没有任何提示。更糟糕的是,它可能会误导;它包含的唯一的函数名称是`callAPromise`,但这并不是正确的错误(尽管这个文件和行数提示依然是有用的)。 219 | 220 | 然而,async/await中的错误堆栈指出了包含错误的函数 221 | 222 | ```javascript 223 | const makeRequest = async() => { 224 | await callAPromise() 225 | await callAPromise() 226 | await callAPromise() 227 | await callAPromise() 228 | await callAPromise() 229 | throw new Error("oops") 230 | } 231 | 232 | makeRequest() 233 | .catch(err => { 234 | console.log(err) 235 | // 输出 236 | // Error: oops at makeRequest (index.js:7:9) 237 | }) 238 | ``` 239 | 240 | 这可能在你本地的开发环境,并且你的文件是在编辑器中打开的,这个可能没有太大的区别。但是在理解生产环境中的服务器的错误日志却是非常有用的。在那样的情况下,知道错误发生在`makeRequest`要远远优于知道错误来自于`then`之后的`then`之后的·`then`... 241 | 242 | #### 6.调试 243 | 244 | 最后很重要的一点是,使用async/await非常重要的一个优点是更加容易调试。调试promise经常是非常痛苦的,主要是如下2个原因 245 | 246 | 1. 你不可以在箭头函数的return表达式下设置断点 247 | 248 | ![debug](https://cdn-images-1.medium.com/max/1000/1*n_V4LaVdBOFgGCbmTR_VKA.png) 249 | 250 | 2. 如果你再一个`.then`块内设置断点,并且你在使用快捷键跳过的时候,debugger不会跳转到下一个`.then`中,因为它仅仅会在同步代码中跳过。 251 | 252 | 在async/await中,你不需要在使用那么多的箭头函数,并且你可以就像在普通的同步代码中跳过。 253 | 254 | ![debug1](https://cdn-images-1.medium.com/max/1000/1*GWYd4eLrs0U96MkNNVB56A.png)) 255 | 256 | ### 总结 257 | 258 | Async/await是近些年JavaScript中最具变革性的特点之一。它让你意识到promise语法的混乱,并且为你提供了一种更为直白的方式。 259 | 260 | ### 值得注意的 261 | 262 | 你可能对使用这个特性的一些有效的怀疑 263 | 264 | * 它让异步代码看起来没有那么明显:我们的眼睛在看到回调或者`.then`的时候意识到这是异步的,当然过一段时间我们可能就适应了,但是在C#中这个特性已经存在多年,熟悉这一点的人应该这点微不足道的,短暂的不便利是值得的。 265 | * Node 7不是一个LTS发布:是的,但是node 8将会在下一个月来临,因此迁移到你的代码到新的版本几乎不要什么额外的工作。 266 | -------------------------------------------------------------------------------- /Npm, yarn以及pnpm的不同之处.md: -------------------------------------------------------------------------------- 1 | # npm, yarn以及pnpm的不同之处 2 | 3 | > 原文:[Overview of differences between npm, yarn and pnpm](https://hackernoon.com/understanding-differences-between-npm-yarn-and-pnpm-31bb6b0c87b3) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 我并不是一个包管理器的专家。相反,直到最近我才意识到`npm`使用的是本地的缓存。在不知道这个时候,我写了这篇名为[我的天--NPM克隆终于有意义了](https://medium.com/@akras14/omg-npm-clone-that-finally-makes-sense-3478588879)并且给出了一些我的不正确的猜想。这些反馈迫使我回头并且重新审视近来这些包管理器的区别。 12 | 13 | 我在过去的5年时间一直都是使用`npm`。我也折腾了下`yarn`当它第一次出来的时候,而且我是通过一个礼拜前的文章“为什么我们应该使用pnpm”来学习`pnpm`的。 14 | 15 | 过去的一周,我一直花时间阅读`npm`,`yarn`以及`pnpm`相关的东西,想总结一下然后分享我的发现。我的目标读者是长期的`npm`用户,并且不愿意花费太多的时间了解有多少种`npm`的替代品,比如我自己。我只会关注这三种最常提及的(对于我)并且不会包括:`ied`,`npm-install`以及`npmd`,因为对于它们我是一无所知。 16 | 17 | 还有重要的一点需要指出,直到写这篇文章的时候,还没有一个具有竞争力的库的目标是替换NPM的**registry**(就是存储包的地方),它们的目的都是替换`npm`命令行客户端,提供另外一个可用的用户界面以及行为,并且其功能也是类似的。 18 | 19 | ## NPM 20 | 21 | [npm](https://github.com/npm/npm)自从Node.js出现的那一天就存在了并且也是造成Node.js这个项目如此成功的原因之一。`npm`团队在让`npm`保持向后兼容以及在多种环境下持续工作都做了很多的工作。 22 | 23 | `npm`的设计理念是根据 [Semantic Versioning (semver)](http://semver.org/),这是一个相当直白的方法可以从他们官网的引用可以看出来。 24 | 25 | 给定一个版本号MAJOR.MINOR.PATCH,增量修改表示: 26 | 27 | - MAJOR版本修改意味着你做出了不兼容的API变化。 28 | - MINOR版本意味着你以向后兼容的方式增加了功能。 29 | - PATCH版本意味着你做出了向后兼容的bug修复。 30 | 31 | `npm`使用一个叫做`package.json`的文件,用户可以存储项目的所有依赖通过运行`npm install --save`。 32 | 33 | 例如,运行`npm install --save loadsh`将会将这一条加入到`package.json`之中。 34 | 35 | ``` 36 | "dependencies": { 37 | "loadsh": "^4.17.4" 38 | } 39 | ``` 40 | 41 | 注意`^`这个loadsh版本号之前的符号。这个符号告诉`npm`安装任何与MAJOR版本相同的包。因此如果一年后我运行`npm install`,`npm`会安装MAJOR版本号为4的最新版本的loadsh。例如,它可以是`loadsh@4.25.5`(`@`是一个npm惯例用来指定包名的版本)。你可以在这看到所有支持的符号: [https://docs.npmjs.com/misc/semver](https://docs.npmjs.com/misc/semver)。 42 | 43 | 这样做的原因是,因为MINOR版本的变动(理论上)应该只是包含向后兼容的滨化。因此安装最新版本的包可能会引入重要的bug或者安全问题,因为最初安装的版本是`4.17.4`。 44 | 45 | 另一方面,它可能会导致多个开发者的机器上安装了不同版本的包,即使他们是共享同一个`package.json`文件,这样会潜在地导致难以调试以及“在我的机器是好的啊”的情形。 46 | 47 | 大多数`npm`包都非常依赖其它的`npm`包。这会导致循环依赖以及增加了版本不匹配的可能。 48 | 49 | 可以通过`npm config set save-exact true`命令来关闭在包的版本前添加`^`的默认行为,但这个只会锁住高层次的依赖。因为每一个引入的包都有它们自己的`package.json`文件,在这里面的依赖可能包含了`^`,没有办法通过`package.json`来保证嵌套的内容。 50 | 51 | 为了解决这个问题,npm提供了一个[shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap)命令。这个命令能够生成一个`npm-shrinkwrap.json`文件,对于所有的包以及嵌套的依赖规定了明确的版本。 52 | 53 | 这也就是说,即使是通过`npm-shrinkwrap.json`这个文件,npm也只是锁住了包的版本而不是包的内容。即使[npm现在阻止用户多次发布相同版本的包](http://blog.npmjs.org/post/77758351673/no-more-npm-publish-f),`npm`管理依然有权利强制更新某些包。 54 | 55 | 下面是 [shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap)文档页面的引用: 56 | 57 | >如果你希望锁定包内包含的指定字节,例如你有百分之百的信心能够重新发布或者构建,那么你应该将你的依赖检查到源代码控制中,或者追求其它的某种能够验证内容而不是版本的机制。 58 | 59 | `npm version 2`过去式对于每个包内所有引入的依赖全部都安装。如果已有一个项目,这个项目引入项目A,项目A引入项目B,项目B引入项目C,那么这个所有依赖的结构树看起来会是下面这样: 60 | 61 | ``` 62 | node_modules 63 | - package-A 64 | -- node_modules 65 | --- package-B 66 | ----- node_modules 67 | ------ package-C 68 | -------- some-really-really-really-long-file-name-in-package-c.js 69 | ``` 70 | 71 | 这个结构可能会变得相当长。这可能仅仅是基于Unix系统上面的一个烦恼,在Windows上已经有很多破解程序能够解决文件路径超过260个字符的问题。 72 | 73 | `npm version 3`通过展平依赖树来解决这个问题,因此这3个项目的结构看起来会是这个样子的: 74 | 75 | ``` 76 | node_modules 77 | - package-A 78 | - package-B 79 | - package-C 80 | -- some-file-name-in-package-c.js 81 | ``` 82 | 83 | 这个变化的结果就是改变了一写长文件的文件路径从 `./node_modules/package-A/node_modules/package-B/node-modules/some-file-name-in-package-c.js` 变化为 `./node_modules/some-file-name-in-package-c.js`。 84 | 85 | 你可以从[这](https://docs.npmjs.com/how-npm-works/npm3)了解更多关于NPM 3依赖的解决方案。 86 | 87 | 这个方法的一个缺点是`npm`现在必须要遍历所有的项目依赖从而决定如何展平`node_modules`文件夹。`npm`被强制为所有使用过的模块建立依赖树,这样做的代价会很大。这也是[导致`npm install`安装速度变慢的原因之一](https://github.com/npm/npm/issues/8826)。(请看文末的更新)。 88 | 89 | 因为我没有仔细关注过`npm`的变化,我猜想NPM速度变慢的原因是我每次运行`npm install`的时候都需要从网上下载所有东西。 90 | 91 | 事实证明,我是错的,并且`npm`**确实**是具有本地缓存的,在其中保存了所有下载包的压缩文件。可以通过`npm cache ls`命令来查看本地缓存的内容。通过本地缓存可以加快安装速度。 92 | 93 | 总而言之,`npm`是一个成熟的,稳定的并且乐于使用的包管理器。 94 | 95 | ## yarn 96 | 97 | [Yarn](https://github.com/yarnpkg/yarn) 是在2016年10月份发布的并且在Github上迅速获取了24K+star。作为对比,[npm](https://github.com/npm/npm) 仅仅只有12K+ star。这个项目具有高资质的开发者比如Sebastian McKenzie ([Babel.js](https://babeljs.io/)) 以及 Yehuda Katz ([Ember.js](https://www.emberjs.com/), [Rust](https://www.rust-lang.org/en-US/), [Bundler](http://bundler.io/) 等等)。 98 | 99 | 从我目前收集的来看,yarn的最初的主要目的是针对`npm`由于之前章节提及的semver相关行为导致的安装的不确定性。然而可预测的依赖树(如果需要的话)能够通过`npm shrinkwarp`来完成,这不是默认的行为并且依赖于开发者了解这一选项并且来进行相应的操作。 100 | 101 | Yarn采取了一个不同的方法。每次`yarn`安装都会生成一个和`npm-shrinkwrap.json`类似的`yarn.lock`文件,但是它是默认产生的。除了常规信息,`yarn.lock`文件还包含了安装内容的检查从而确保使用相同版本的包。 102 | 103 | 因为yarn是一个才重写的`npm`客户端,开发者能够适宜地并行所有需要的操作并且增加一些改进,这同时也显著提升了整体地安装时间。我认为速度地加快是`yarn`流行的主要原因。 104 | 105 | 像`npm`一样,`yarn`也使用了本地缓存。但是不像`npm`,`yarn`在安装已经缓存的依赖的时候并不需要网络连接,提供了一种`offline`模式。这个特性[在npm上自从2012年就收到了请求](https://github.com/npm/npm/issues/2568),但是一直没有得到解决。 106 | 107 | Yarn提供一些其它的好处。比如,它允许聚合项目中使用的所有的licence,并且很容易看到。 108 | 109 | 有意思的一点事,`yarn`文档对于`npm`态度的转变自从其变得流行之后。 110 | 111 | 最初的[yarn发布的时候](https://code.facebook.com/posts/1840075619545360)说的安装`yarn`的步骤是: 112 | 113 | > 最容易开始运行的方式是: 114 | > 115 | > ``` 116 | > npm install -g yarn 117 | > yarn 118 | > ``` 119 | 120 | 现在yarn[关于安装yarn的方式是](https://yarnpkg.com/en/docs/install#alternatives-tab): 121 | 122 | > 注意:不建议使用npm来进行安装。npm是非确定性的,包是没有签名的,npm仅仅是做了基本的SHA1 哈希并没有做任何整体性检查,这对于安装系统级别的应用是有风险的。 123 | > 124 | > 鉴于以上原因,强烈建议你通过适合你操作系统的安装方法来安装yarn。 125 | 126 | 以这种速度,即使`yarn`宣布它们自己的registry从而让开发者缓慢淘汰`npm`我都不觉得惊讶。 127 | 128 | 同样也是由于`yarn`,`npm`终于一是到它们需要密切关注那些强烈请求的issue。[NPM最初对于yarn发布的回应](http://blog.npmjs.org/post/151660845210/hello-yarn)在我看来是“它是可爱的”。现在,当我重新看那个被强烈要求的我之前提到过的“离线”特性已经有在被积极地解决,[在我们讨论这一点的时候](https://github.com/npm/npm/commit/8cf4c662903ce84a24138acf3cc37083aecac08b)。 129 | 130 | ## pnpm 131 | 132 | 正如我之前所提及的那样,我只是才知道[pnpm](https://github.com/pnpm/pnpm) 不久通过阅读Zoltan Kochan的[“为什么我们应该使用pnpm?”](https://www.kochan.io/nodejs/why-should-we-use-pnpm.html),他就是npm的作者。 133 | 134 | 我不想设计到过多的细节(因为这篇文章已经很长了),但是你可以从我[最初的博文](https://medium.com/@akras14/omg-npm-clone-that-finally-makes-sense-3478588879)中可以了解一些以及[推特上的讨论](https://twitter.com/akras14/status/855474658832900096)。 135 | 136 | **但是** 137 | 138 | 我想指出的是`pnpm`比[npm以及yarn都要快](https://github.com/pnpm/node-package-manager-benchmark)。 139 | 140 | 为什么它这么快的原因?因为它采用了巧妙的方式,利用硬链接和符号链接,以避免复制所有本地缓存的源文件,这是打败yarn在性能上最主要的一方面。 141 | 142 | 使用链接并不容易,需要考虑一系列的问题。 143 | 144 | 正如Sebastian[在推特上](https://twitter.com/sebmck/status/855553631680069637)所指出的,他最初是想在`yarn`里面使用符号链接,但最后因为[很多原因](https://github.com/yarnpkg/yarn/issues/1761#issuecomment-259706202)来对抗yarn。 145 | 146 | 同时,这个项目在Github上也具有2K+star,`pnpm`能够让链接为很多人工作。 147 | 148 | 另外,自从[2017年3月](https://www.kochan.io/nodejs/why-should-we-use-pnpm.html)它提供了所有`yarn`提供的优点,包括离线模式以及确定性安装。 149 | 150 | ## 结论 151 | 152 | 我认为`yarn`和`pnpm`的开发者都做了很好的工作。我个人的偏好是确定性的安装,因为我喜欢自己掌控并且我不喜欢惊喜。 153 | 154 | 无论最后竞争的结果是什么(这也提醒了我[io.js](https://iojs.org/en/) fork),我感谢`yarn`给`npm`带来的这些麻烦因此尘埃落定之前还有很多选择余地。 155 | 156 | 我也认为`yarn`可能很早之前就考虑过硬链接以及软链接。我想知道的是`yarn`团队针对这个想法会做些什么,取决于`pnpm`造成的杀伤以及用户对于安装速度重视的程度。 157 | 158 | 我确实认为总的来说`yarn`是一个安全的选择,但是`pnpm`在某些案例上可能是一个更好的选择。比如,对于一个需要运行很多集成测试并且希望尽可能提高安装依赖速度的中小型团队。 159 | 160 | 最后值得说得一点是,我认为`npm`依然提供了对于大多数用户案例非常有用的解决方案。大多数开发者可以继续只使用`npm`客户端。 161 | 162 | 无论是任何情况,我都感谢所有的努力保持生态健康的竞争者。当公司竞争的时候,获利的是用户。 163 | 164 | 来自于一下[@ReBeccaOrg](https://twitter.com/ReBeccaOrg)推特的更新。 165 | 166 | > - FYI, 展平不是“遍历整棵树”的来源。遍历整棵树是关于自愈。 167 | > - 和npm@2相比,它减缓了速度。 168 | > - 如果你通过`rm -fr`来删除嵌套的依赖并且通过`npm install`来安装,你会注意到这可能帮你解决问题。 169 | > - 现在事实证明,npm@1-@npm@4缓存是缓慢的,非常慢。慢的超乎想象。经常往往是比在一个快速网络中下载快一点点。因此随着npm@5的重写(自从npm1.5就开始计划)它突然变得快多了。 170 | > - yarn通过沙箱可以伤你免于http://registry.npmjs.org 敌对的限制,但是并不抱进一步的保证。 -------------------------------------------------------------------------------- /如何写一个webpack插件.md: -------------------------------------------------------------------------------- 1 | # 如何写一个webpack插件 2 | 3 | > 原文:[how to write a plugin](https://github.com/webpack/docs/wiki/how-to-write-a-plugin) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 插件能够将webpack引擎的全部潜力暴露给第三方的开发者。通过使用阶段构建回调,开发者能够将他们自己的行为引入到webpack的构建过程中。构建插件比构建loader更高级,因为你需要理解一些webpack低层次的内部钩子。准备好阅读一些源代码吧! 12 | 13 | ## Compiler以及Compilation 14 | 15 | 在开发插件的时候最重要的两个资源就是`compiler`和`compilation`对象。理解它们的角色是拓展webpack引擎重要的第一步。 16 | 17 | - `compiler`对象代表了完整的配置的webpack环境。一旦开启webpack之后,这个对象就被构建了,并且这个对象会使用所有操作设置,包括options, loaders, 以及plugins来进行配置。当将一个插件应用到webpack环境中,这个插件将会获得一个对于这个compiler的引用。使用这个compiler可以访问主要的webpack环境。 18 | - 一个`compilation`对象代表版本资源的一次构建。当运行webpack开发中间件的时候,每次检测到文件变化的时候都会产生一个新的compilation,因此会生成一系列编译后的资源。Compilation表示有关模块资源,已编译资源,已更改文件和监视依赖关系的当前状态的信息。该compilation还提供了许多回调点,插件可以选择执行自定义操作。 19 | 20 | 这两个组件是任何webpack插件(特别是`compilation`)的内部一部分,因此开发者熟悉这些源代码文件之后将会受益非凡: 21 | 22 | - [Compiler Source](https://github.com/webpack/webpack/blob/master/lib/Compiler.js) 23 | - [Compilation Source](https://github.com/webpack/webpack/blob/master/lib/Compilation.js) 24 | 25 | ## 基本的插件架构 26 | 27 | 插件是实例对象,并且在它们的prototype上,会有一个`apply`方法。当安装这个插件的时候,这个`apply`方法就会被webpack compiler调用。这个`apply`会给出一个对于潜在的webpack compiler的引用,保证了对于compiler回调的访问。一个简单的插件结构如下: 28 | 29 | ```javascript 30 | function HelloWorldPlugin(options) { 31 | // Setup the plugin instance with options... 32 | } 33 | 34 | HelloWorldPlugin.prototype.apply = function(compiler) { 35 | compiler.plugin('done', function() { 36 | console.log('Hello World!'); 37 | }); 38 | }; 39 | 40 | module.exports = HelloWorldPlugin; 41 | ``` 42 | 43 | 接着是安装这个插件,只要在你的webpack 配置`plugins`数组里面添加一个实例: 44 | 45 | ```javascript 46 | var HelloWorldPlugin = require('hello-world'); 47 | 48 | var webpackConfig = { 49 | // ... config settings here ... 50 | plugins: [ 51 | new HelloWorldPlugin({options: true}) 52 | ] 53 | }; 54 | ``` 55 | 56 | ## 访问compilation 57 | 58 | 使用compiler对象,你可能绑定提供那个对于每一个新的compilation引用的回调。这些compilation提供对于在构建过程中对于很多步骤钩子的回调。 59 | 60 | ```javascript 61 | function HelloCompilationPlugin(options) {} 62 | 63 | HelloCompilationPlugin.prototype.apply = function(compiler) { 64 | 65 | // Setup callback for accessing a compilation: 66 | compiler.plugin("compilation", function(compilation) { 67 | 68 | // Now setup callbacks for accessing compilation steps: 69 | compilation.plugin("optimize", function() { 70 | console.log("Assets are being optimized."); 71 | }); 72 | }); 73 | }; 74 | 75 | module.exports = HelloCompilationPlugin; 76 | ``` 77 | 78 | 对于更多关于`compiler`以及`compilation`上的回调以及其他重要的对象,请参考 [[plugins API|plugins]] 文档。 79 | 80 | ## 异步compilation plugins 81 | 82 | 有一些compilation插件步骤是异步的,并且当你的插件完成运行的时候,传递一个*必须*被调用的回调函数。 83 | 84 | ```javascript 85 | function HelloAsyncPlugin(options) {} 86 | 87 | HelloAsyncPlugin.prototype.apply = function(compiler) { 88 | compiler.plugin("emit", function(compilation, callback) { 89 | 90 | // Do something async... 91 | setTimeout(function() { 92 | console.log("Done with async work..."); 93 | callback(); 94 | }, 1000); 95 | 96 | }); 97 | }; 98 | 99 | module.exports = HelloAsyncPlugin; 100 | ``` 101 | 102 | ## 一个简单的例子 103 | 104 | 一旦我们可以锁定到webpack compiler以及每一个独立的compilation,我们可以利用引擎本身就能发挥无穷的潜力。我们能够重新格式化存在的文件,创建衍生文件,或者制造全新的资源。 105 | 106 | 让我们写一个简单的能够生成一个新的打包文件`filelist.md`的插件例子;这个文件的内容会列出所有存在我们build之内的资源文件。这个插件可能看起来是这个样子的: 107 | 108 | ```javascript 109 | function FileListPlugin(options) {} 110 | 111 | FileListPlugin.prototype.apply = function(compiler) { 112 | compiler.plugin('emit', function(compilation, callback) { 113 | // Create a header string for the generated file: 114 | var filelist = 'In this build:\n\n'; 115 | 116 | // Loop through all compiled assets, 117 | // adding a new line item for each filename. 118 | for (var filename in compilation.assets) { 119 | filelist += ('- '+ filename +'\n'); 120 | } 121 | 122 | // Insert this list into the Webpack build as a new file asset: 123 | compilation.assets['filelist.md'] = { 124 | source: function() { 125 | return filelist; 126 | }, 127 | size: function() { 128 | return filelist.length; 129 | } 130 | }; 131 | 132 | callback(); 133 | }); 134 | }; 135 | 136 | module.exports = FileListPlugin; 137 | ``` 138 | 139 | ## 有用的插件模式 140 | 141 | 插件允许在webpack构建系统内发挥无尽可能的定制化。这允许你创建自定义的资源类型,执行特殊的构建调整,或者设置在使用中间件的时候进一步提升webpack运行时间。下面的webpack的一些特性在开发插件的时候变得很有用。 142 | 143 | ### 探索assets, chunks, modules, 以及dependencies 144 | 145 | 在compilation完成之后,compilation中的所有的结构都可能被遍历。 146 | 147 | ```javascript 148 | function MyPlugin() {} 149 | 150 | MyPlugin.prototype.apply = function(compiler) { 151 | compiler.plugin('emit', function(compilation, callback) { 152 | 153 | // Explore each chunk (build output): 154 | compilation.chunks.forEach(function(chunk) { 155 | // Explore each module within the chunk (built inputs): 156 | chunk.modules.forEach(function(module) { 157 | // Explore each source file path that was included into the module: 158 | module.fileDependencies.forEach(function(filepath) { 159 | // we've learned a lot about the source structure now... 160 | }); 161 | }); 162 | 163 | // Explore each asset filename generated by the chunk: 164 | chunk.files.forEach(function(filename) { 165 | // Get the asset source for each file generated by the chunk: 166 | var source = compilation.assets[filename].source(); 167 | }); 168 | }); 169 | 170 | callback(); 171 | }); 172 | }; 173 | 174 | module.exports = MyPlugin; 175 | ``` 176 | 177 | - `compilation.modules`: 在compilation中由模块(构建输入)组成的数组。每个模块管理来自于源代码库中的源文件的构建。 178 | - `module.fileDependencies`: 包含在模块中的源文件路径数组。 这包括源JavaScript文件本身(例如:`index.js`)以及所需的所有依赖项资源文件(样式表,图像等)。 查看依赖关系对于查看哪些源文件属于模块很有用。 179 | - `compilation.chunks`: Compilation中由chunks组成的数组(构建输出)。 每个chunk管理最终渲染资源的组合。 180 | - `chunk.modules`: 包含在一个chunk中的模块数组。 通过扩展,您可以查看每个模块的依赖关系,以查看传递到chunk中的原始源文件 181 | - `chunk.files`: 由chunk生成的输出文件名的数组。 您可以从`compilation.assets`表访问这些资源。 182 | 183 | ### 检测观察图 184 | 185 | 在运行webpack中间件时,每个compilation都包含一个`fileDependencies`数组(正在监视的文件)和一个将观察文件路径映射到时间戳的`fileTimestamps`哈希。 这些对于检测compilation中哪些文件已更改非常有用: 186 | 187 | ```javascript 188 | function MyPlugin() { 189 | this.startTime = Date.now(); 190 | this.prevTimestamps = {}; 191 | } 192 | 193 | MyPlugin.prototype.apply = function(compiler) { 194 | compiler.plugin('emit', function(compilation, callback) { 195 | 196 | var changedFiles = Object.keys(compilation.fileTimestamps).filter(function(watchfile) { 197 | return (this.prevTimestamps[watchfile] || this.startTime) < (compilation.fileTimestamps[watchfile] || Infinity); 198 | }.bind(this)); 199 | 200 | this.prevTimestamps = compilation.fileTimestamps; 201 | callback(); 202 | }.bind(this)); 203 | }; 204 | 205 | module.exports = MyPlugin; 206 | ``` 207 | 208 | 您还可以将新的文件路径传入观察图,以便在这些文件更改时接收compilation触发器。 只需将有效的文件路径推送到`compilation.fileDependencies`数组中即可将其添加到观察列表中。 注意:在每个compilation中重建`fileDependencies`数组,因此您的插件必须将自己观察的依赖项推送到每个编译中,以使它们保持监视。 209 | 210 | ### 改变的chunks 211 | 212 | 与观察图类似,通过跟踪它们的哈希值,可以在compilation中监视更改的块(或模块)。 213 | 214 | ```javascript 215 | function MyPlugin() { 216 | this.chunkVersions = {}; 217 | } 218 | 219 | MyPlugin.prototype.apply = function(compiler) { 220 | compiler.plugin('emit', function(compilation, callback) { 221 | 222 | var changedChunks = compilation.chunks.filter(function(chunk) { 223 | var oldVersion = this.chunkVersions[chunk.name]; 224 | this.chunkVersions[chunk.name] = chunk.hash; 225 | return chunk.hash !== oldVersion; 226 | }.bind(this)); 227 | 228 | callback(); 229 | }.bind(this)); 230 | }; 231 | 232 | module.exports = MyPlugin; 233 | ``` -------------------------------------------------------------------------------- /git-undo.md: -------------------------------------------------------------------------------- 1 | >原文:[How to undo (almost) anything with Git](https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/) 2 | > 3 | >译者:[madneal](https://github.com/madneal) 4 | > 5 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 6 | > 7 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 8 | 9 | ![](https://github.blog/wp-content/uploads/2019/03/community-twitter.png?resize=1201%2C630) 10 | 11 | 任何版本控制系统最有用的功能之一就是能够“撤消”错误。在 Git 中,“撤消”可能意味着许多略有不同的事情。 12 | 13 | 当你进行新的 commit 时,Git 会及时存储你的仓库在该特定时刻的快照;之后,你可以使用 Git 返回到项目的早期版本。 14 | 15 | 在这篇文章中,我将介绍一些你可能想要“撤消”所做更改的常见场景,以及使用 Git 执行此操作的最佳方法。 16 | 17 | ## 撤销一个“public”修改 18 | 19 | **场景:** 你刚刚运行了 `git push`,将你的修改 push 到 GitHub,现在意识到有一个 commit 有问题。你想把这个 commit 撤销。 20 | 21 | **撤销:** `git revert ` 22 | 23 | **结果:** `git revert` 将创建一个与给定 SHA 相反的新 commit。如果旧 commit 是“matter”,则新 commit 是“anti-matter”——旧 commit 中删除的任何内容都将添加到新 commit 中,而旧 commit 中添加的任何内容都将在新 commit 中删除。 24 | 25 | 这是 Git 最安全、最基本的“撤消”场景,因为它不会更改历史记录,因此你现在可以使用 `git push` 来提交新的 commit来撤消错误的 commit。 26 | 27 | ## 修复上一个 commit message 28 | 29 | **场景:** 你刚刚打错了最新一条 commit message,你使用 `git commit -m "Fxies bug #41"`, 但在 `git push` 之前你意识到应该写 `Fixes bug #42`。 30 | 31 | **撤销:** `git commit --amend` 或 `git commit --amend -m "修复 bug #42"` 32 | 33 | **结果:** `git commit --amend` 将更新最新 commit 并将其替换为新 commit ,将新 commit 与之前提交的 commit 的内容相结合。若当前没有任何 stage 内容,这只是重写了之前的 commit 消息。 34 | 35 | ## 撤销本地修改 36 | 37 | **场景:** 猫走过键盘并以某种方式保存了更改,然后编辑器崩溃。不过,你还没有 commit 这些修改。你想要撤消该文件中的所有内容 - 只需返回到上次 commit 时的样子即可。 38 | 39 | **撤消:** `git checkout -- ` 40 | 41 | **结果:** `git checkout` 将工作目录中的文件更改为 Git 之前保存的状态。你可以提供要返回的分支名称或特定 `SHA`,或者默认情况下,Git 会假设你要切换到 `HEAD`,即当前分支上的最后一次 commit。 42 | 43 | 请记住:你以这种方式“撤消”的任何更改实际上都会消失。它们从未被 commit ,因此 Git 无法帮助我们稍后恢复它们。确保你知道你在这里扔掉了什么! (也许使用 `git diff` 来确认。) 44 | 45 | ## 重置本地修改 46 | 47 | **场景:** 你在本地进行了一些 commit (尚未 push),但一切都很糟糕,你想要撤消最后三个 commit - 就像它们从未发生过一样。 48 | 49 | **撤消方式:** `git reset ` 或 `git reset --hard ` 50 | 51 | **结果:** `git reset` 将仓库的历史记录一直回溯到指定的 `SHA`。就好像这些 commit 从未发生过一样。默认情况下,`git reset` 保留工作目录。 commit 已消失,但内容仍在磁盘上。这是最安全的选择,但通常,你会希望一次“撤消” commit 和更改 - 这就是 `--hard` 参数的作用。 52 | 53 | ## 撤销本地修改后恢复 54 | 55 | **场景:** 你进行了一些 commit ,执行了 `git reset --hard` 来“撤消”这些更改(见上文),然后意识到:你想要恢复这些更改! 56 | 57 | **撤消:** `git reflog` 和 `git reset` 或 `git checkout` 58 | 59 | **结果:** `git reflog` 是恢复项目历史记录的绝佳资源。你可以通过 reflog 恢复几乎任何内容(任何你 commit 的内容)。 60 | 61 | 你可能熟悉 `git log` 命令,它显示 commit 列表。 `git reflog` 类似,但显示 `HEAD` 更改的时间列表。 62 | 63 | 一些注意事项: 64 | 65 | * `HEAD` 只有在你切换分支时,使用 `git commit` 进行 commit 并使用 `git reset` 取消 commit 时,HEAD 会更改,但是当你 `git checkout -- ` 时 `HEAD` 不会变化(来自较早的场景 - 如前所述,这些更改从未 commit ,因此 `reflog` 无法帮助我们恢复这些更改)。 66 | * `git reflog` 不会一直有效。 Git 会定期清理“无法访问”的对象。不要指望在 `reflog` 一直发现几个月前的 commit 。 67 | * 你的转发记录是你的,并且只属于你。你不能使用 `git reflog` 来恢复其他开发人员未 push 的 commit 。 68 | 69 | ![reflog*](https://github.blog/wp-content/uploads/2015/06/f6b9f054-d891-11e4-8c53-838eff9f40ae.png?resize=1429%2C644) 70 | 71 | 那么……如何使用 reflog 来“恢复”之前“撤消”的一个或多个 commit ?这取决于你到底想要完成什么: 72 | 73 | * 如果你想恢复项目当时的历史记录,请使用 `git reset --hard ` 74 | * 如果你想在工作目录中重新创建一个或多个文件,而不更改历史记录,请使用 `git checkout -- ` 75 | * 如果你想将其中一个 commit 重放到存储库中,请使用 `gitcherry-pick ` 76 | 77 | ## 再一次,通过分支 78 | 79 | **场景:** 你提交了一些 commit ,然后意识到你在 master 分支上。你希望可以在 `feature` 分支上提交 commit 。 80 | 81 | **撤消:** `git branch feature`,`git reset --hard origin/master` 和 `git checkout feature` 82 | 83 | **结果:** 你可能习惯使用 `git checkout -b ` 创建新分支 - 这是创建新分支并立即 checkout 的流行快捷方式 - 但你不想立即切换到刚刚创建的分支。在这里,`git branch feature` 创建了一个名为 `feature` 的新分支,指向你最近的 commit ,但让你依然在 master 分支上。 84 | 85 | 接下来,在任何新 commit 之前, `git reset --hard` 将 `master` 回退到 `origin/master`。不过不用担心,它们仍然可以使用。 86 | 87 | 最后,`git checkout` 切换到新 `feature` 分支,你最近的所有工作都完好无损。 88 | 89 | ## 分支省时大法 90 | 91 | **场景:** 你基于 `master` 分支创建了一个新的 `feature` 分支,但是 `master` 远远落后于 `origin/master`。现在 `master` 分支与 `origin/master` 同步,你希望 `feaute` 的 commit 现在就开始,而不是远远落后。 92 | 93 | **撤消方式:** `git checkout feature` 和 `git rebase master` 94 | 95 | **结果:** 你可以使用 `git reset`(无 `--hard`,有意保留磁盘上的更改)然后 `git checkout -b ` 来完成此操作,然后重新 commit 更改,但这样,你会丢失 commit 历史记录。有一个更好的方法。 96 | 97 | 98 | `git rebase master` 做了几件事: 99 | 100 | * 首先,它找到当前分支和 `master` 分支之间的共同祖先。 101 | * 然后它将当前的分支重置为该祖先,将所有后续 commit 保存在保留区域中。 102 | * 然后它将当前分支前放到 `master` 的末尾,并在 `master` 最后一次 commit 后重放保留区域的 commit 。 103 | 104 | ## 批量撤消/重做 105 | 106 | **场景:** 你从一个方向开始功能开发,但在中途,你意识到另一种解决方案更好。你有十几个 commit ,但你只想要其中的一些,不想要其它的了。 107 | 108 | **撤消:** `git rebase -i ` 109 | 110 | **结果:** `-i` 将 `rebase` 置于“交互模式”。它像上面讨论的 rebase 一样开始,但在重放任何 commit 之前,它会暂停并允许你在重放时轻易修改每个 commit 。 111 | 112 | `rebase -i` 将在默认文本编辑器中打开,并显示正在应用的 commit 列表,如下所示: 113 | 114 | ![rebase-interactive1](https://github.blog/wp-content/uploads/2015/06/f6b1ab88-d891-11e4-97c1-e0630ac74e74.png?resize=1459%2C495) 115 | 116 | 前两列是关键:第一列是为第二列中的 SHA 标识的 commit 选择的命令。默认情况下,`rebase -i` 假设每个 commit 都使用 `pick` 命令。 117 | 118 | 要删除 commit ,只需在编辑器中删除该行即可。如果你不再希望项目中存在错误 commit ,则可以删除上面的第 1 行和第 3-4 行。 119 | 120 | 如果要保留 commit 的内容但编辑 commit 消息,可以使用 `reword` 命令。只需将第一列中的单词 `pick` 替换为单词 `reword` (或只是 `r`)。现在可能你觉得要重写 commit 消息,但这行不通—— `rebase -i` 会忽略 `SHA` 列之后的所有内容。之后的文字实际上只是为了帮助我们记住 `0835fe2` 的含义。当你完成 `rebase -i` 后,系统将提示你输入需要写入的任何新 commit 消息。 121 | 122 | 如果你想将两个 commit 合并在一起,你可以使用 `squash` 或 `fixup` 命令,如下所示: 123 | 124 | ![rebase-interactive2](https://github.blog/wp-content/uploads/2015/06/f6b605ca-d891-11e4-98cf-d567ca9f4edc.png?resize=1449%2C339) 125 | 126 | `squash` 和 `fixup` 向上合并 commit —— 使用这两个命令的 commit 将被合并到紧邻其之前的 commit 中。在这种情况下,`0835fe2` 和 `6943e85` 将合并为一个 commit ,然后 `38f5e4e` 和 `af67f82` 将合并为另一 commit 。 127 | 128 | 当你选择 `squash` 时,Git 会提示我们给新的组合 commit 一条新的 commit 消息;`fixup` 将为新 commit 提供列表中第一个 commit 的消息。在这里,你知道 `af67f82` 是一个“ooops” commit ,因此你只需按原样使用来自 `38f5e4e` 的 commit 消息,但你将为通过组合 `0835fe2` 和 `6943e85` 获得的新 commit 编写一条新消息。 129 | 130 | 当你保存并退出编辑器时,Git 将按从上到下的顺序应用你的 commit 。你可以通过在保存之前更改 commit 顺序来更改 commit 应用的顺序。如果你愿意,你可以通过如下安排将 `af67f82` 与 `0835fe2` 组合起来: 131 | 132 | ![rebase-interactive3](https://github.blog/wp-content/uploads/2015/06/f6b4a9d2-d891-11e4-9ac9-10039c031d06.png?resize=1445%2C326) 133 | 134 | ## 修复较早的 commit 135 | 136 | **场景:** 你未能在早期 commit 中包含文件,如果早期 commit 能够以某种方式包含你遗漏的内容,那就太好了。你还没有 push ,但这不是最近的 commit ,所以你不能使用 `commit --amend`。 137 | 138 | **撤销:** `git commit --squash ` 和 `git rebase --autosquash -i ` 139 | 140 | **结果:** `git commit --squash` 将创建一个新的 commit ,其中包含类似 `squash! Earlier commit`。(你可以手动创建带有类似消息的 commit ,但 `commit --squash` 可以节省你的打字时间。) 141 | 142 | 如果你不想提示你为组合 commit 编写新的 commit 消息,你也可以使用 `git commit --fixup`。在这种情况下,你可能会使用 `commit --fixup`,因为你只想在 rebase 期间使用早期 commit 的 commit 消息。 143 | 144 | `rebase --autosquash -i` 将启动交互式 `rebase` 编辑器,但该编辑器将用任何 `sqush!` 和 `!fixup!` commit 已经与 commit 列表中的 commit 目标配对,如下所示: 145 | 146 | ![rebase-autosquash](https://github.blog/wp-content/uploads/2015/06/f6a7a1d8-d891-11e4-8784-c32262ff54da.png?resize=1446%2C294) 147 | 148 | 使用 `--squash` 和 `--fixup` 时,你可能不记得要修复的 commit 的 SHA,只记得它是一到五个 commit 前的。你可能会发现使用 Git 的 `^` 和 `~ `运算符特别方便。 `HEAD^` 是 HEAD 之前的一次 commit 。 `HEAD~4` 是 HEAD 之前的四次 commit ,或者总共是五次向后 commit 。 149 | ## Stop tracking a tracked file 150 | 151 | ## 停止跟踪被跟踪的文件 152 | 153 | **场景:** 你不小心将 `application.log` 添加到仓库中,现在每次运行应用程序时,Git 都会报告 `application.log` 中存在未暂存的更改。你将 `*.log` 放入 `.gitignore` 文件中,但它仍然存在 - 你如何告诉 git “撤消”跟踪此文件中的更改? 154 | 155 | **撤消:** `git rm --cached application.log` 156 | 157 | **结果:** 虽然 `.gitignore` 阻止 Git 跟踪文件的更改,甚至阻止它注意到以前从未跟踪过的文件的存在,但一旦添加并 commit 了文件,Git 将继续注意到该文件中的更改。同样,如果你使用 `git add -f` 来“强制”,或覆盖 `.gitignore`,Git 将继续跟踪更改。以后你不必使用 `-f`` 来添加它。 158 | 159 | 如果你想从 Git 的跟踪中删除那个应该被忽略的文件, `git rm --cached` 将从跟踪中删除它,但在磁盘上保留该文件不变。由于它现在被忽略,你将不会在 `git status` 中看到该文件,也不会意外地再次 commit 该文件的更改。 160 | 161 | 这就是使用 Git 撤消任何操作的方法。要了解有关此处使用的任何 Git 命令的更多信息,请查看相关文档: 162 | 163 | * [checkout](http://git-scm.com/docs/git-checkout) 164 | * [commit](http://git-scm.com/docs/git-commit) 165 | * [rebase](http://git-scm.com/docs/git-rebase) 166 | * [reflog](http://git-scm.com/docs/git-reflog) 167 | * [reset](http://git-scm.com/docs/git-reset) 168 | * [revert](http://git-scm.com/docs/git-revert) 169 | * [rm](http://git-scm.com/docs/git-rm) 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # articles-translator [:memo:](https://github.com/madneal/articles-translator/edit/master/README.md) 2 | 3 | Translate distinct technical blogs. 4 | 5 | If interested, you can watch or star it, fork is not a siginificant way. Of course, The best way is to join translation.:tada::tada::tada: Any good article, please issue. I do really hope anyone can join me to continue this work. Provide original articles or join the translation work, either one is appreciated.[@neal](mailto:bing@stu.ecnu.edu.cn) 6 | 7 | Moreover, for the export of blogs in Medium, I will suggest the Chrome extension [Export to Markdown](https://chrome.google.com/webstore/detail/export-to-markdown/dodkihcbgpjblncjahodbnlgkkflliim?utm_source=chrome-ntp-icon&authuser=1). 8 | 9 | * [NilAway:实用的 Go Nil Panic 检测方式](https://github.com/madneal/articles-translator/blob/master/NilAway.md) 10 | * [我认为Bootstrap是有害的](https://github.com/madneal/articles-translator/blob/master/Bootstrap_considered_harmful.md) 11 | * [javascript中的对象字面量为啥这么酷](https://github.com/madneal/articles-translator/blob/master/javascript%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%AD%97%E9%9D%A2%E9%87%8F%E4%B8%BA%E5%95%A5%E8%BF%99%E4%B9%88%E9%85%B7.md) 12 | * [Latex 专业的参考](https://github.com/madneal/articles-translator/blob/master/Latex%20%E4%B8%93%E4%B8%9A%E7%9A%84%E5%8F%82%E8%80%83.md) 13 | * [你可能不知道谷歌浏览器开发工具的其他用处](https://github.com/madneal/articles-translator/blob/master/%E4%BD%A0%E5%8F%AF%E8%83%BD%E4%B8%8D%E7%9F%A5%E9%81%93%E8%B0%B7%E6%AD%8C%E6%B5%8F%E8%A7%88%E5%99%A8%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%E7%9A%84%E5%85%B6%E4%BB%96%E7%94%A8%E5%A4%84.md) 14 | * [Vue in 2016](https://github.com/madneal/articles-translator/blob/master/Vue%20in%C2%A02016.md) 15 | * [head标签里面的一切](https://github.com/madneal/articles-translator/blob/master/head%E6%A0%87%E7%AD%BE%E9%87%8C%E9%9D%A2%E7%9A%84%E4%B8%80%E5%88%87.md) 16 | * [在Windows安装MongoDB社区版](https://github.com/madneal/articles-translator/blob/master/mongodb%E5%AE%89%E8%A3%85.md) 17 | * [原生模块加载](https://github.com/madneal/articles-translator/blob/master/%E5%8E%9F%E7%94%9F%E6%A8%A1%E5%9D%97%E5%8A%A0%E8%BD%BD.md) 18 | * [原生ECMAScript 模块](https://github.com/madneal/articles-translator/blob/master/%E5%8E%9F%E7%94%9FECMAScript%20%E6%A8%A1%E5%9D%97.md) 19 | * [10个开发新手应该熟悉的github仓库](https://github.com/madneal/articles-translator/blob/master/10%E4%B8%AA%E5%BC%80%E5%8F%91%E6%96%B0%E6%89%8B%E5%BA%94%E8%AF%A5%E7%86%9F%E6%82%89%E7%9A%84github%E4%BB%93%E5%BA%93.md) 20 | * [JavaScript中Async/Await优于Promise的6个原因](https://github.com/madneal/articles-translator/blob/master/Javascript%E4%B8%ADAsync-Await%E4%BC%98%E4%BA%8EPromise%E7%9A%846%E4%B8%AA%E5%8E%9F%E5%9B%A0.md) 21 | * [Twitter Lite以及大规模的高性能React渐进式网络应用](https://github.com/madneal/articles-translator/blob/master/Twitter%20Lite%E4%BB%A5%E5%8F%8A%E5%A4%A7%E8%A7%84%E6%A8%A1%E7%9A%84%E9%AB%98%E6%80%A7%E8%83%BDReact%E6%B8%90%E8%BF%9B%E5%BC%8F%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8.md) 22 | * [Service worker介绍](https://github.com/madneal/articles-translator/blob/master/Service%20worker%E4%BB%8B%E7%BB%8D.md) 23 | * [Npm, yarn以及pnpm的不同之处](https://github.com/madneal/articles-translator/blob/master/Npm%2C%20yarn%E4%BB%A5%E5%8F%8Apnpm%E7%9A%84%E4%B8%8D%E5%90%8C%E4%B9%8B%E5%A4%84.md) 24 | * [Github Pages以及单页面应用](https://github.com/madneal/articles-translator/blob/master/Github%20Pages%E4%BB%A5%E5%8F%8A%E5%8D%95%E9%A1%B5%E9%9D%A2%E5%BA%94%E7%94%A8.md) 25 | * [基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]](https://github.com/madneal/articles-translator/blob/master/%E5%9F%BA%E4%BA%8EVue%20JS%2C%20Webpack%20%E4%BB%A5%E5%8F%8AMaterial%20Design%E7%9A%84%E6%B8%90%E8%BF%9B%E5%BC%8Fweb%E5%BA%94%E7%94%A8%20%5BPart%201%5D.md) 26 | * [如何写一个webpack插件](https://github.com/madneal/articles-translator/blob/master/%E5%A6%82%E4%BD%95%E5%86%99%E4%B8%80%E4%B8%AAwebpack%E6%8F%92%E4%BB%B6.md) 27 | * [通过利用immutability的能力编写更安全和更整洁的代码](https://github.com/madneal/articles-translator/blob/master/%E9%80%9A%E8%BF%87%E5%88%A9%E7%94%A8immutability%E7%9A%84%E8%83%BD%E5%8A%9B%E7%BC%96%E5%86%99%E6%9B%B4%E5%AE%89%E5%85%A8%E5%92%8C%E6%9B%B4%E6%95%B4%E6%B4%81%E7%9A%84%E4%BB%A3%E7%A0%81.md) 28 | * [采用Flow以及TypeScript](https://github.com/madneal/articles-translator/blob/master/%E9%87%87%E7%94%A8Flow%E4%BB%A5%E5%8F%8ATypeScript.md) 29 | * [JavaScript是如何工作的:引擎,运行时间以及回调的概述](https://github.com/madneal/articles-translator/blob/master/JavaScript%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%EF%BC%9A%E7%B3%BB%E5%88%97%E4%B8%80.md) 30 | * [JavaScript是如何工作的:内存管理以及如何处理四种常见的内存泄漏](https://github.com/madneal/articles-translator/blob/master/JavaScript%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9A%E7%B3%BB%E5%88%97%E4%B8%89.md) 31 | * [你并不知道 Node](https://github.com/madneal/articles-translator/blob/master/%E4%BD%A0%E5%B9%B6%E4%B8%8D%E7%9F%A5%E9%81%93Node.md) 32 | * [Vue 2.5 发布了](https://github.com/madneal/articles-translator/blob/master/Vue%202.5%20%E5%8F%91%E5%B8%83%E4%BA%86.md) 33 | * [你应该了解的5个 Logstash Filter 插件](https://github.com/madneal/articles-translator/blob/master/%E4%BD%A0%E5%BA%94%E8%AF%A5%E4%BA%86%E8%A7%A3%E7%9A%845%E4%B8%AA%20Logstash%20Filter%20%E6%8F%92%E4%BB%B6.md) 34 | * [出去就餐并且理解Express.js的基本知识](https://github.com/madneal/articles-translator/blob/master/%E5%87%BA%E5%8E%BB%E5%B0%B1%E9%A4%90%E5%B9%B6%E4%B8%94%E7%90%86%E8%A7%A3Express.js%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md) 35 | * [理解 CSS Flexbox](https://github.com/madneal/articles-translator/blob/master/%E7%90%86%E8%A7%A3CSS%20Flexbox.md) 36 | * [🚀 宣布 Parcel:一个快速,零配置的 Web 应用打包工具 📦](https://github.com/madneal/articles-translator/blob/master/%F0%9F%9A%80%20%E5%AE%A3%E5%B8%83%20Parcel%EF%BC%9A%E4%B8%80%E4%B8%AA%E5%BF%AB%E9%80%9F%EF%BC%8C%E9%9B%B6%E9%85%8D%E7%BD%AE%E7%9A%84%20Web%20%E5%BA%94%E7%94%A8%E6%89%93%E5%8C%85%E5%B7%A5%E5%85%B7%20%F0%9F%93%A6.md) 37 | * [你真的理解 grok 吗](https://github.com/madneal/articles-translator/blob/master/%E4%BD%A0%E7%9C%9F%E7%9A%84%E7%90%86%E8%A7%A3grok%E5%90%97%EF%BC%9F.md?) 38 | * [送给 ES6 开发者的7个hack](https://github.com/madneal/articles-translator/blob/master/%E9%80%81%E7%BB%99%20ES6%20%E5%BC%80%E5%8F%91%E8%80%85%E7%9A%847%E4%B8%AAhack%20.md) 39 | * [从仓库中移除敏感信息](https://github.com/madneal/articles-translator/blob/master/%E4%BB%8E%E4%BB%93%E5%BA%93%E4%B8%AD%E7%A7%BB%E9%99%A4%E6%95%8F%E6%84%9F%E4%BF%A1%E6%81%AF.md) 40 | * [JavaScript 是如何工作的:渲染引擎以及优化建议](https://github.com/madneal/articles-translator/blob/master/JavaScript%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9A%E6%B8%B2%E6%9F%93%E5%BC%95%E6%93%8E%E4%BB%A5%E5%8F%8A%E4%BC%98%E5%8C%96%E5%BB%BA%E8%AE%AE.md) 41 | * [JavaScript 是如何工作的: Service Workers, 它们的生命周期和使用案例](https://github.com/madneal/articles-translator/blob/master/Javascript%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9A%E7%B3%BB%E5%88%97%E5%85%AB.md) 42 | * [JavaScript 是如何工作的:在网络层如何优化性能和安全](https://github.com/madneal/articles-translator/blob/master/JavaScript%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9A%E7%B3%BB%E5%88%97%E5%8D%81%E4%BA%8C.md) 43 | * [Elasticsearch 团队开发章程](https://github.com/madneal/articles-translator/blob/master/Elasticsearch%E5%9B%A2%E9%98%9F%E5%BC%80%E5%8F%91%E7%AB%A0%E7%A8%8B.md) 44 | * [使用 ELK Stack 建设SIEM](https://github.com/madneal/articles-translator/blob/master/%E4%BD%BF%E7%94%A8ELK%20Stack%E5%BB%BA%E8%AE%BESIEM.md) 45 | * [正则表达式入门](https://github.com/madneal/articles-translator/blob/master/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%85%A5%E9%97%A8.md) 46 | * ["隐写术" - 深入研究 PDF混淆漏洞](https://github.com/madneal/articles-translator/blob/master/%E9%9A%90%E5%86%99%E6%9C%AF-%E6%B7%B1%E5%85%A5%E7%A0%94%E7%A9%B6PDF%E6%B7%B7%E6%B7%86%E6%BC%8F%E6%B4%9E.md) 47 | * [2019 年针对 API 安全的 4 点建议](https://github.com/madneal/articles-translator/blob/master/2019%E5%B9%B4%E9%92%88%E5%AF%B9API%E5%AE%89%E5%85%A8%E7%9A%844%E7%82%B9%E5%BB%BA%E8%AE%AE.md) 48 | * [DNS 缓存投毒](https://github.com/madneal/articles-translator/blob/master/DNS%E7%BC%93%E5%AD%98%E6%8A%95%E6%AF%92.md) 49 | * [理解跨域资源共享](https://github.com/madneal/articles-translator/blob/master/%E7%90%86%E8%A7%A3%E8%B7%A8%E5%9F%9F%E8%B5%84%E6%BA%90%E5%85%B1%E4%BA%AB.md) 50 | * [Pornhub Web 开发者访谈](https://github.com/madneal/articles-translator/blob/master/%E5%AF%B9Pornhub%E7%9A%84Web%E5%BC%80%E5%8F%91%E8%80%85%E7%9A%84%E9%87%87%E8%AE%BF.md) 51 | * [GMail 中的 XSS 漏洞](https://github.com/madneal/articles-translator/blob/master/XSS.md) 52 | * [火眼红队工具遭窃](https://github.com/madneal/articles-translator/blob/master/%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE%E7%81%AB%E7%9C%BC%E7%BA%A2%E9%98%9F%E5%B7%A5%E5%85%B7.md) 53 | * [微软开源对于 Solorigate 活动捕获的开源 CodeQL 查询](https://github.com/madneal/articles-translator/blob/master/mst-codeql.md) 54 | * [CircleCI 20230104 安全事件报告](https://github.com/madneal/articles-translator/blob/master/circleci-incident.md) 55 | * [如何使用 Git 撤消(几乎)任何操作](https://github.com/madneal/articles-translator/blob/master/git-undo.md) 56 | 57 | ## Articles need translation 58 | 59 | 60 | # License 61 | 62 | [MIT](https://github.com/madneal/articles-translator/blob/master/LICENSE) 63 | -------------------------------------------------------------------------------- /Elasticsearch团队开发章程.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch 团队开发章程 2 | 3 | >原文:[Elasticsearch Team Development Constitution](https://github.com/elastic/engineering/blob/master/development_constitution.md) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ## 前言 12 | 13 | 我们作为 Elasticsearch 核心开发人员团队希望尽可能快地向可靠,健壮,安全,可扩展且易于使用的系统迁移。我们希望为创新而努力,取代传统的构造和功能,删除脆弱的代码,并致力于改善用户体验,同时在我们快速变化的同时保持用户增长。 14 | 15 | 对于我们来说,拥有一个团队的前进方向的共识是非常重要的,甚至更重要的是团队为什么要走上一条特定的路。当 Elasticsearch 创立之初时,它具有无尽的灵活性,易用性和丰富的 API。我们这帮年轻的团队成立了一家公司,并且突然用户数井喷式发展。支持组织几乎无法满足越来越多的客户,这是幸福的烦恼。然而,随着用户数量的增长,事情发生的可能性也越来越大,不幸的是,这比我们聘用支持工程师的速度要快得多。我们了解到,大多数灵活性来自宽松处理,从大多数情况下可行的功能,但不是全部。例如,用户可以使用请求发送的脚本基本上是一个远程代码执行引擎,如果出错,它是致命的。即使最基本的功能,比如设置,也非常灵活,但非常脆弱。在没有单位的情况下指定一个数字是很好的,除非许多用户不知道默认单位是什么。我们只是试图做正确的事情,结果证明并不是总是对的。 16 | 17 | 现在我们处于不同的位置。我们的用户基数比 2013 年的用户基数大得多,但我们的支持机构并没有以同样的速度增长。是的,我们处理比 2013 年更多的支持案例,但这在我们当时的系统中是不可能的。现在我们已经从一个脆弱而灵活的系统转向了范围较窄的软件。我们定义了更多的边界:更严格的输入验证,允许我们对权限进行细粒度控制的安全模型,甚至还有一个插件模型,可以以极大的灵活性来添加风险更高的功能。 18 | 19 | 但等等,我们还差得远呢!仍然有无穷无尽的问题会造成致命的后果。聚合可以通过一个请求来撑爆服务器。用户感觉需要运行 30+GB 堆的 Elasticsearch。我们仍然提供了 27 种指定布尔值的不同方式。这份清单还有其它内容... 20 | 21 | 我们对我们的用户,支持组织,云托管团队和第三方提供商负有巨大责任,提供可靠,稳健,安全且易于使用的系统。出于这个原因,我们都应该努力创新,取代传统的构造和功能,删除脆弱的代码,并改善用户体验。我们与其他公司相比的优势是我们的创新,创新需要速度。我们必须在留住用户的同时下采取行动并接受变革创新。 22 | 23 | 以下章节是用于设计,重构或从 Elasticsearch 代码库中删除代码的原则和指导原则的集合。这些点是无序的,大部分是未分类的,应该被看作是 Elasticsearch 团队内软件开发的一个组成部分。 24 | 25 | ## 设计特性 26 | 27 | * *过程优于结果*。我们多年来一直遵循这种方法,这使我们能够随着时间的推移做出巨大的变化,而不会因大量的请求而产生巨大的响应。例如,补齐建议程序在 Elasticsearch 的早期版本中添加,而不支持实时更新和特定的删除。这意味着删除 Elasticsearch 中的文档不会立即反映在建议中。这是一个很难的问题,大约三年后,我们增加了对 Lucene 建议器和 Elasticsearch 的 bitset 过滤器的支持。与此同时,对于许多用户来说,这是一个可以接受的解决方案,修复了许多错误,并朝着基于文档的建议器发展。这就是过程优于结果。 28 | 29 | * *为今天设计!谨慎使用抽象*。计算机科学教授教育学生以灵活性和信息隐藏的名义广泛使用抽象层。当然 Elasticsearch 广泛使用抽象; 没有任何涉及数百万行代码的项目可以以其他方式进行工作并生存。但经验表明,过度或过早的抽象可能与过早优化一样有害。抽象应该用于所需的级别,不要再进一步。 30 | 31 | 作为一个简单的练习,假设一个函数,它的参数总是被所有调用者传递为零。人们可以保留这个参数,以防万一有人最终需要使用它提供的额外的灵活性。但是那个时候,代码从来没有注意到的机会是好的 - 因为它从未被使用过。或者当需要额外的灵活性时,它不会以符合程序员早期预期的方式进行。我们应该定期提交补丁以删除未使用的参数; 一般而言,他们不应该添加在首位。(来源于 https://www.kernel.org/doc/Documentation/development-process/4.Coding) 32 | 33 | * *开始简单; 不要聪明*。每个人都希望编写一流的,前沿的,快速的代码,长时间保持鲁棒性,优雅和高效的代码。不幸的是,这不会在一夜之间发生。就像我们在跑步之前学会走路一样。一项新功能应该以最简单的方式开始。即使希望防止移动所有分片将索引从8分片缩减到4分片,最好有一个稳固的共享基础结构,它要求所有分片位于同一个节点上。特殊分配逻辑可以在稍后的版本中发布。 34 | 35 | * *注意:删除代码很困难*。即使删除最小的功能也是非常困难的。将代码添加到代码库并明智地选择添加的内容时请注意这一点。我们可能需要坚持多年,或者当我们试图将其删除时,将会影响到很多用户。 36 | 37 | * *严格,明确,可靠,简单*。Elasticsearch 有添加宽松,模糊,不可靠和复杂选项的历史。关于这些在不久前发生了变化。乍一看,它似乎有助于对用户友好,但是其成本巨大。它带有一些组合式的选项和代码路径,它们没有经过测试,并且隐藏了错误。一个完美的例子是指定一个布尔值的 gazillion 选项。 有人会认为这与将该值与字符串“true”或“false”进行比较一样简单,如果不匹配,我们会抛出异常。不,它接受值“false”,“0”,“no”和“off”,如果它们不匹配,则将其解释为“true”。什么可能会出错?如果你添加代码,请尽可能以最简单,最严格,明确和可靠的方式进行。 38 | 39 | * *坚守核心职责* 我们的系统坚持*稳固*和*可靠*特性至关重要。为此,我们需要牢记我们的核心责任是分布式可扩展搜索引擎。例如,我们曾经提供一个名为 site-plugins 的有限 Web 服务器,但它并不代表我们的核心职责,所以我们将其删除。当功能与使 Elasticsearch 成为更好的分布式可扩展搜索引擎相一致时,它变得更加坚实可靠。(同样的原则适用于我们所有的产品。) 40 | 41 | * *你是专家; 就表现得像一名专家*。Elasticsearch 已经变得流行起来。用户基数非常庞大,呈指数级增长。高级用户正在减少,因此我们现在的核心职责之一就是简化 API 使用并降低“搬起石头砸自己的脚”的风险。 我们的核心 API 提供了很大的灵活性,这使得它们很容易被误用。其结果往往是性能下降,集群中断和错误结果。展望未来,我们应该利用我们的经验和对系统的深入了解来预防这些缺陷。构建可以很好地完成单一职责的 API 和功能。不要将其设计为解决其他问题的解决方法。 42 | 43 | * *独立构建功能*。始终优先将功能添加为插件,而不是将功能添加到内核。制定明确的 API 和扩展的最好方法就是使用它们。为了达到可维护的核心,我们必须保持其精益。我们的插件模型允许类加载器隔离以及对第三方组件的专用权限。一个孤立的实现总是可取的。如果需要通过发布来传送,它可以是一个模块。 44 | 45 | * *先移除再修复*。通常情况下,对于危险或者有陷阱的特性的移除往往停滞不前,因为没有其它的替代功能。我们将移除这些功能并优先重新实现它们,就像它们是新功能一样。如果这些功能很重要,我们将会在下一个发布中推迟重新实现。如果不是,它可能会被重新实现,直到它们被发布。或者它们可能永远不会被重新实现,随着时间的推移而被遗忘。消除危险功能对组织的成功至关重要。例如,*delete-by-query* 反复导致大量中断,需要数天才能进行调试和修复。它的移除可能为我们节省了大量的金钱和时间,而我们没有花费在我们的客户身上。鉴于我们的用户基数增长迅速,即使该决定不受欢迎,我们也有责任为用户做出正确的决定。当涉及到安全性,集群稳定性和数据损坏时,*先移除*方法是强制性的。 46 | 47 | * *默认速度很快; 慢是可选的*。性能是我们业务的关键。慢被认为是难以解决的。这是一个非常困难的话题,因为例如 O(n) 对于10k 文件来说是可以接受,但不能用于 10m。一个完美的例子是脚本中的 `_source` 访问。 有些脚本(搜索实例)应该不允许访问 `_source `,因为它会加载每个评分文档的 JSON 源。脚本每次执行都需要访问磁盘。像这样的功能必须默认禁用,或者不应该在系统的性能关键部分提供。始终存在原型设计,小型文档集,小型网上商店等等的争论。然而,我们在这里的信息应该集中在重新定义和未来改进我们的默认设置,从而淘汰这些 API。 48 | 49 | * *关注升级体验* 随着基于时间的发布,升级体验对我们来说至关重要,因为我们希望用户尽快切换到新版本。过去我们遇到了很多问题,导致用户遭遇了长时间的集群重启。 我们的功能开发和改进想法应着重于平滑前进的道路。 50 | 51 | * *突破主要的,而不是小的*。主要版本必须完成重大更改。我们试图将变化的范围限制在不会同时突破太多,特别是如果我们正在接近 GA 日期。 如果我们接近,可以将突破性改变来推进到下一个大的变更。 52 | 53 | * *自下而上测试*。如果你编写代码,首先编写单元测试。写很多。编写单元测试代码,以便可以编写许多代码。集成测试是最后一步。专注于添加更多快速执行且易于调试的测试,如单元测试。这对于开发者的速度来说至关重要。 54 | 55 | * *考虑Java API 专家 API*。 除 HTTP 客户端及其专用 API,Elasticsearch 中的所有 API 外,所有扩展点和插件都是专业 API。 因此,专家用户可以处理 API更改和清除。 确保人们不使用已弃用的 API 的最可靠方法是将其删除。不要犹豫,特别是当它是一个内部 API 时。非专家用户应始终使用 REST 界面。 56 | 57 | * *重要的是,对所有的代码保持质疑,并拥抱错误*。每个人都会编写必须在某个时刻修复,重构或删除的代码。但是大多数情况下,代码的有效半衰期很短。添加注释,说明为什么以某种方式完成事情。当我们开发一个功能时,我们永远无法知道问题的全部范围或所有用例。 58 | 59 | 当有人批评代码时,他们不是批评你,所以对事不对人。帮助他们理解你为什么这样写。当有人重写你写的代码时,并不是不认可你的想法。有一次,Mike 向 Lucene 提交了一个变化,Adrien 在两天后就将它废弃了!当其他人对你写的代码感兴趣时,这很好,这意味着代码是活的。随着代码成为一个日益增长,蓬勃发展的存在,可以持续看到代码的改进。 60 | 61 | 不要害怕犯错,更重要的是,不要让恐惧使你无法添加一些不完全正确的东西。将错误和失败视为*反馈*,*发现*和*知识*可以使我们的产品更好。 62 | 63 | * *不要害怕重大改变*。通常解决问题的办法很难。最难的部分是正确解决。它伴随着大量的工作,风险和系统变化,这些变化会影响到其他人- 主要是用户。 优先使用增量更改(请参阅*过程优于结果*),但愿意在不可能进行增量更改的大块中进行大的更改。 64 | 65 | * *不要害怕说不*。 Elasticsearch 现在无法接受所有变化。如果我们试图让每个人都快乐,我们就会卡住并瘫痪。有些东西只是不适用于像 Elasticsearch 这样的系统。考虑 [参加](https://github.com/elastic/elasticsearch/pull/3278)或*实型隔离*。对于这些,我们必须说*谢谢,但是不用了!* 66 | 67 | * *只接受可扩展的功能*。我们经常获得在单节点情况下可以正常工作的功能请求(例如,连接或精确基数聚合),但鉴于Elasticsearch的分布式特性,这将是一场灾难。 这些功能请求应始终被拒绝,因为它们违反了我们在可伸缩性和分布式特性方面的核心 Elasticsearch 责任。原则上,我们不添加仅适用于单节点情况下的功能。 68 | 69 | * *始终从梦想出发*。首先了解什么是完美的解决方案是明智的,即使它涉及向后中断或删除核心功能,并稍后用更好的解决方案替换它们。有时甚至需要时间才能实现理想。同样的道理,考虑最简单的解决方案是明智的选择,在很多情况下,最大的优势在于最接近最简单的解决方案。 70 | 71 | * *关注错误报告*。在软件开发中,很多东西都是二元的。如果它没有像预期的那样工作,它应该快速而艰难地失败。关注良好的错误报告;避免吞噬异常,声明检查的异常,并强制调用者处理这种情况。保护具有实际检查方法的先决条件。异常是方法合同的一部分!如果我们不知道或记录可能会发生什么异常,那么我们就不知道该方法的行为。添加 check/javadoc 并尽量让这个更好。看看 JDK 代码的例子,甚至我们用作参考的 Lucene 代码在这里也不是一个好例子。理解如何使你的代码更快,例如在该方法中预先检查数组索引不仅更加清晰,而且快速而且坚定地失败,并且还可以消除边界检查(“支配性测试”)。在报告错误时,问问自己: a)如果你正在调试问题,你希望看到什么消息,以及 b)什么信息可以使运营中的生产支持团队有足够的洞察力来诊断问题。 72 | 73 | * *为代码提供文档*。你可能认为你的代码是显而易见的,但它可能不是。对那些不熟悉这些成千上万行代码的人给予高层次的概述,这样你们就可以分而治之。记录在包,类和方法级别做什么的总结。 如果你认为你自己的代码是棘手或难以处理的,那就更多尝试其它补救措施。长期存活的代码只写一次,但多次阅读和重读! 74 | 75 | * *默认为私有*。 Java 的访问级别是封装代码的好方法:将接口/合约与实现细节分开。私有的是最好的,私有包装是好的,公众是最后的手段。要小心你公开的内容,以便你的类或 API 简单易用。 76 | 77 | * *每一个变化都值得审阅*。我们的系统很复杂,每一个变化都可能产生潜在的副作用。我们希望每个人都努力工作并思考问题,但有时候会错过暗示。每个变更都应该提出并且至少得到一个 LGTM。 对于复杂的变化,两位审阅员更好。 在一些小组中,两个是 LGTM 的最小数量,三个是复杂的变化。编码人员和审阅人分担与变更相关的失败责任;这鼓励仔细审查。有时候某个功能意外失败,因为它依赖的功能已经改变或损坏。我们应该为所有客户承担失败和意外问题,而不是责怪一些人。 78 | 79 | * *敢于打破规则*。有时代码必须打破规则。如果你的评论包含一个150个字符的表格,可能会更容易理解五次。试图强制执行“DRY”的恶意抽象可能会比简单的代码重复更糟糕! 80 | 81 | ## 和人们互动 82 | 83 | * *精确和尊重地表达你的意见*。总是分享你要说的话,但为其它意见留下余地。总是解释你的理由。命令的口吻往往会结束对话。像“这将永远不会工作”和“这是愚蠢的”短语是懒惰和不精确的。说:“我认为这将是有问题的,因为......”。不要说“这是错误的”; 说“我认为这是错误的,因为...”。 不要说“这真的需要吗?”; 问“为什么需要这样做?”不要说“我不打开其他任何东西”或“没有什么可讨论的”。请参阅关于否决权的观点。 84 | 85 | * *保持友善*。书面形式很难。你的意图对于读者可能不是很明显。努力清楚地解释你的推理。如果你没有很好的解释,请尽快道歉。认为是误解而不是恶意。如果对传达你的想法有任何疑问,请进行视频或语音聊天。 86 | 87 | 来自于[保持友善](http://boz.com/articles/be-kind.html): 88 | 89 | * 保持友善从根本上来说是对你对周围人的影响负责。它要求你注意自己的感受,并体谅你的存在影响他们的方式。这和表面友好不一样。这不是表面上的赞美。这并不意味着贬低你的意见。它不应该减少你展示他们的激情。 90 | 91 | * *感谢人们*。当有人完成了一项好的工作请说出来。花点时间来包含一些细节,说明为什么你认为做出真诚和具体的工作是一件好事。 92 | 93 | (意识到一些视频是反向教材: [如何像老板一样指派任务](https://www.youtube.com/watch?v=h3MPewsk5PU&t=5m55s)) 94 | 95 | * *权力随之而来的是责任*。你有权否决。否决权或者换句话说'-1'是一个强烈的呼吁。只有当你100%确信不应做出某种改变时,才将其作为最后的手段。如果你只是不同意或不喜欢改变,不要使用它。**请注意,否决权将终止 issue/change 的进展,除非撤回**,因此要意识到否决权的严重性。 96 | 97 | 用明智的话来解释你的反对意见。你的否决权必须出于技术原因。准备好讨论和解释。被否决的改变被提议者认为是好的,他们值得讨论。 当然,他们也应该有机会用他们的理由来说服你。在过去,这种健康的讨论实际上以撤销否决权而告终。 98 | 99 | * *珍惜激情*。一些同事拥有无限激情。不幸的是,他们并不总是具有无限的耐心。如果讨论横向进行,改变沟通渠道总是好事。面对面的交流在这样的开发环境中至关重要。例如,我们的一些代码清理工作持续数月。想想设置重构或删除谷歌 guice。如果你在某个问题上争论不休,请记住另一个人可能花了数月的时间,你可能会错过大局。很难确保两个人都在同一步调上!如果有疑问,请在 slack 上深入讨论或者继续。 100 | 101 | * *对压力感同身受*。你将面临无休止的争论的情况。你会看到人们不会使用礼貌的声音的情况。不要接受它,但试着在事后谈论它,并原谅。 102 | 103 | * *对我们的行为准则小组报告滥用评论*。如果你看到辱骂性评论,即使你不是对话的一部分,请报告(推回)。不要激发讨论,也不要提供更多滥用评论的论坛。结束讨论并通知他人支持你。如果你不想这样做,那么直接联系其他人为你做这件事很好。使用 github 表情符号(和反应表情符号)放大其他人的反馈。然后继续进行技术论证。保持大度,帮助他人减少滥用或侵略性评论的影响。 104 | 105 | * *如有疑问,请提问。* Elasticsearch 有很多复杂的领域。如果你有疑问,或者你不确定如何解决某个问题,如果你甚至不知道如何处理问题或者卡住了,请去寻求帮助。通过会话向其他人解释问题甚至可能有助于意识到问题的解决方案是完全不同的解决方案。 106 | 107 | * *通过相互交谈来解决冲突。接受决定,即使不是你的,并继续前进*。我们都是充满激情和自信的人。这就是我们擅长我们的工作并推动代码的原因。这也意味着我们不会总是同意。谈论事情并尝试考虑其它方面。几乎总是有其它方式可以让双方都开心。在最糟糕的情况下,有些时候没有达成共识,领导层不得不打电话。 [不同意并提交](https://www.google.com/url?q=https://www.amazon.jobs/principles&sa=D&ust=1470304258318000&usg=AFQjCNEtnDcPw2eh-GlszSmtsrGfZtSoMw)。 记住:没有什么是最终的,只要错了就有可能会发生改变。 108 | 109 | 受启发于: 110 | 111 | [Zen of Python](https://en.wikipedia.org/wiki/Zen_of_Python) 112 | 113 | [Contributor Covenant](http://contributor-covenant.org/) 114 | 115 | [Amazon’s Leadership Principles](https://www.amazon.jobs/principles) 116 | 117 | [Rust’s Code of Conduct](https://www.rust-lang.org/en-US/conduct.html), [Rust video on Conduct](https://youtu.be/dIageYT0Vgg?t=7m2s) 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /理解CSS Flexbox.md: -------------------------------------------------------------------------------- 1 | ## 理解 CSS Flexbox 2 | 3 | > 原文:[Understanding CSS Flexbox](https://codeburst.io/understanding-css-flexbox-d6162885fefe) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ![](https://cdn-images-1.medium.com/max/2000/1*xpjy9vmoYYR_5RGPBqQoIw.png) 12 | 13 | 你有没有想过如何最好地使用 flexbox 来排列元素? 如果你再也不能 忍受 CSS Float hack,让我们深挖一下,并学习如何使用 Flexbox。 14 | 15 | ![oOLUe.png](https://s1.ax1x.com/2017/12/06/oOLUe.png) 16 | 17 | ## 什么是 Flexbox? 18 | 19 | 让我们来注意两个与 Flexbox 属性配合使用的重要元素; Flex Container 和 Flex Item。 20 | 21 | Flex Container 显然被设置为父元素,而 Flex Items 是 Flex Container 的直接子元素。 22 | 23 | 因此,Flexbox 布局使得 Flex Container 能够调整 Flex Item 的宽度和高度,以适应各种显示设备和屏幕尺寸的可用空间。 24 | 25 | > 如上所述,在 ***flex container*** 中存在一个或者多个 ***flex item***。 26 | 27 | ## **Flex Container 中的 Flexbox 属性** 28 | 29 | 1. **Display: Flex** 30 | 31 | 在下图中,我们有四个框,默认情况下每个框是一个块元素; 也就是说,他们应该占据整行。 Flexbox 可以在所有容器的直接孩子(即四个盒子)上启用 flex 属性,而四个框则以内联方式显示。 32 | 33 | ![](https://cdn-images-1.medium.com/max/2000/1*hb6tOl-7bpB_xOV2XDG3GA.png) 34 | 35 | .container { 36 | display: flex; 37 | } 38 | 39 | 2. **Flex Direction** 40 | 41 | 我们经常尝试垂直或水平对齐菜单列表项。 然后,我们必须使用列表项,然后将无序列表的css属性显示为 ***display-inline***。 42 | 43 | 但是通过Flex Container 的 Flex-direction,它可以帮助我们指定容器内的 Flex Item 的对齐方向(比如从左到右或从右到左)。 以下是 flex-direction 的属性: 44 | 45 | ***row, row-reverse, column and column-reverse.*** 46 | 47 | ![](https://cdn-images-1.medium.com/max/2000/1*vPkSdz6kf2yFFPLN_0oBYg.png) 48 | 49 | ​ display: flex; 50 | ***flex-direction: column;*** 51 | 52 | .container { 53 | display: flex; 54 | flex-direction: column; /** lays the Flex Items vertically from top to bottom **/ 55 | } 56 | 57 | ![](https://cdn-images-1.medium.com/max/2000/1*hb6tOl-7bpB_xOV2XDG3GA.png) 58 | 59 | ​ display: flex; 60 | ***flex-direction: row;*** 61 | 62 | .container { 63 | display: flex; 64 | flex-direction: row; /** Places the Flex Items from left to right **/ 65 | } 66 | 67 | 3. **Flex Wrap** 68 | 69 | 让我们假设我们在我们团队的页面上有一个包含12张个人资料照片的画廊,我们可以选择将所有12张图片连续放置,或者将图片包装放在其他行上。 70 | 71 | 借助 Flex-wrap,我们可以将所有图像保留在一行上,或者轻松地包装到另一行中。 以下是 flex-wrap 的属性: 72 | 73 | ***nowrap, wrap and wrap-reverse.*** 74 | 75 | ![images are not wrapped to another line and this looks terrible](https://cdn-images-1.medium.com/max/2000/1*10-Z2OdPKwYS3QDVNFfs-Q.png) 76 | 77 | ​ 图片没有包装到另一行并且这看起来很糟糕 78 | 79 | .container { 80 | display: flex; 81 | flex-wrap: nowrap; /** default property. all profile pictures will be on one line **/ 82 | } 83 | 84 | ![images will wrap onto new lines](https://cdn-images-1.medium.com/max/2000/1*49fmrP7OosgNa7l6RI_bVQ.png) 85 | 86 | ​ 图片将会包装到新行中 87 | 88 | .container { 89 | display: flex; 90 | flex-wrap: wrap; /** images will wrap onto another line if necessary, from top to bottom **/ 91 | } 92 | 93 | 4. **Justify Content** 94 | 95 | 对于 Justify-content 具有以下属性: 96 | 97 | ***flex-start, flex-end, center, space-around and space-between.*** 98 | 99 | ![](https://cdn-images-1.medium.com/max/2000/1*DT3irNO28CMlTeEOByVTJQ.png) 100 | 101 | .container { 102 | display: flex; 103 | justify-content: flex-start; 104 | border: 1px solid black; 105 | } 106 | 107 | ![](https://cdn-images-1.medium.com/max/2000/1*VoPMWkKRRb-X7X8FfXR7eA.png) 108 | 109 | .container { 110 | display: flex; 111 | justify-content: flex-end; 112 | border: 1px solid black; 113 | } 114 | 115 | ![](https://cdn-images-1.medium.com/max/2000/1*FZeechhQD1IVta2G_VJgLg.png) 116 | 117 | .container { 118 | display: flex; 119 | justify-content: center; 120 | border: 1px solid black; 121 | } 122 | 123 | ![](https://cdn-images-1.medium.com/max/2000/1*5ZLXFMHJ3C250ZzlovArhw.png) 124 | 125 | .container { 126 | display: flex; 127 | justify-content: space-between; 128 | border: 1px solid black; 129 | } 130 | 131 | ![](https://cdn-images-1.medium.com/max/2000/1*xA5jAgh2HzPNYeqXYXDF1w.png) 132 | 133 | .container { 134 | display: flex; 135 | justify-content: space-around; 136 | border: 1px solid black; 137 | } 138 | 139 | **5. Align Items** 140 | 141 | 就像对齐内容一样,align-items 帮助我们对齐横轴上的flex项目,即从上到下垂直排列,在某些情况下从下到上排列。 142 | 143 | 我们有以下属性的对齐项目: 144 | 145 | ***flex-start, flex-end, center, stretch and baseline.*** 146 | 147 | ![cards align on the top of the cross-axis](https://cdn-images-1.medium.com/max/2000/1*qVoeSLvHQf63vZ_cfG7N-g.png) 148 | 149 | .container { 150 | height: 50vh; 151 | display: flex; 152 | flex-wrap: wrap; 153 | justify-content: center; 154 | align-items: flex-start; 155 | border: 1px solid black; 156 | } 157 | 158 | ![cards align on the end of the cross-axis](https://cdn-images-1.medium.com/max/2000/1*hD5JeOPEfPPawpixwZzgVA.png) 159 | 160 | .container { 161 | height: 50vh; 162 | display: flex; 163 | flex-wrap: wrap; 164 | justify-content: center; 165 | align-items: flex-end; 166 | border: 1px solid black; 167 | } 168 | 169 | ![](https://cdn-images-1.medium.com/max/2000/1*vzpHtRSgzSMCRIzNjP7oGQ.png) 170 | 171 | .container { 172 | height: 50vh; 173 | display: flex; 174 | flex-wrap: wrap; 175 | justify-content: center; 176 | align-items: baseline; 177 | border: 1px solid black; 178 | } 179 | 180 | ![cards are of different heights but they still align at the center](https://cdn-images-1.medium.com/max/2000/1*TOWFH-Duvckx2PZRAp9A5A.png) 181 | 182 | ​ 不同高度的图片仍然居中 183 | 184 | .container { 185 | height: 50vh; 186 | display: flex; 187 | flex-wrap: wrap; 188 | justify-content: center; 189 | align-items: center; 190 | border: 1px solid black; 191 | } 192 | 193 | ![Flex item img height has to be set to auto else the height property will override the stretch property.](https://cdn-images-1.medium.com/max/2000/1*bKsKgNEN37PyxMnw9DNEMw.png) 194 | 195 | Flex item img 的 height 必须设置为 auto,否则 height 属性会覆盖 stretch 属性 196 | 197 | .container { 198 | height: 50vh; 199 | display: flex; 200 | flex-wrap: wrap; 201 | justify-content: center; 202 | align-items: stretch; 203 | border: 1px solid black; 204 | } 205 | 206 | ## **Flexbox Examples** 207 | 208 |
209 |
1
210 |
2
211 |
3
212 |
4
213 |
214 | 215 | .wrapper { 216 | height: 100%; 217 | display: flex; 218 | flex-wrap: wrap; 219 | justify-content: flex-start; 220 | align-items: center; 221 | border: 1px solid black; 222 | } 223 | .card { 224 | display: flex; 225 | justify-content: center; 226 | align-items: center; 227 | width: 120px; 228 | height: 120px; 229 | background-color: green; 230 | margin: 10px; 231 | color: #fff; 232 | font-size: 36px; 233 | font-weight: 600; 234 | } 235 | .card-1 { 236 | background-color: red; 237 | } 238 | .card-2 { 239 | background-color: brown; 240 | } 241 | .card-3 { 242 | background-color: purple; 243 | } 244 | .card-4 { 245 | background-color: green; 246 | } 247 | 248 | [codepen](https://codepen.io/jidelambo/pen/MOmmwV) 249 | 250 | display: flex; 251 | flex-wrap: wrap; 252 | justify-content: flex-start; 253 | align-items: center; 254 | 255 | 2) 256 | 257 | .wrapper { 258 | height: 100%; 259 | display: flex; 260 | flex-wrap: wrap; 261 | justify-content: space-between; 262 | align-items: center; 263 | border: 1px solid black; 264 | } 265 | .card { 266 | display: flex; 267 | justify-content: center; 268 | align-items: center; 269 | width: 120px; 270 | height: 120px; 271 | background-color: green; 272 | margin: 10px; 273 | color: #fff; 274 | font-size: 36px; 275 | font-weight: 600; 276 | } 277 | .card-1 { 278 | background-color: red; 279 | } 280 | .card-2 { 281 | background-color: brown; 282 | } 283 | .card-3 { 284 | background-color: purple; 285 | } 286 | .card-4 { 287 | background-color: green; 288 | } 289 | 290 | [codepen](https://codepen.io/jidelambo/pen/XzRRNy) 291 | 292 | ## **总结** 293 | 294 | 我们已经讨论了Flex Container 的 flexbox 属性及其对齐 flex item 的影响。 我希望在后面的文章中更多地介绍Flex Item 中的 Flexbox propeties。 295 | 如果这篇文章对你有帮助,请给予一些绿色的鼓掌或下面的评论。 296 | 感谢你的阅读! 297 | 298 | -------------------------------------------------------------------------------- /Github Pages以及单页面应用.md: -------------------------------------------------------------------------------- 1 | # Github Pages以及单页面应用 2 | 3 | > 原文:[GitHub Pages and Single-Page Apps](https://dev.to/_evansalter/github-pages-and-single-page-apps) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 单页面应用(SPAs)现在特别火。它们使构建功能丰富,高性能的web应用变得特别容易。因此你可以自己去构建一个SPA,但是依然存在一个问题。你应该在什么地方托管呢? 12 | 13 | 这篇文章分为两个部分。第一部分,是列出了我用过的不同的SPA托管方法以及它们的优缺点。第二部分,是我使用Github Pages托管SPA的经验,包括我遇到的问题。我希望能够帮助读者在如何托管他们的app的时候做出一个知情决定,并且如果它们使用任何我谈论的方法,它们可以从我的错误中有所学习。 14 | 15 | 如果你希望专注于Github Pages并且跳过其它的方法,你可以直接跳到第四节:Github Pages。 16 | 17 | ## 1. Google App Engine 18 | 19 | 我没有深入web开发直到我开始我现在的工作。是的,我了解一些HTML以及CSS,并且我曾经上过大学的web开发课。然而,我对这些并不是很感兴趣直到我在工作领域使用这些技能。 20 | 21 | 在我的工作中,我们所有的应用都是使用App Engine来构建的。我们使用Python版本,Jinja2是我们的模板语言,Knockout.js是我们的前端代码。之后对于在App Engine中开发我觉得很舒适。我熟悉它,我已经到了可以相对快速,轻松地将新应用程序整合在一起的地步。 22 | 23 | 现在,回到SPAs。在2016的夏天,我开始从事于 [Roll Up Tracker](https://www.rolluptracker.com/)。Roll Up Tracker是一种Angular2的web-app,它能够让你追踪你在Tim Hortons举办的Rim To Win赛季中的胜利和损失。自然的,当我开始这个项目的时候我决定将它托管在App Engine中。这可能有一点奇怪,利用一个完整的App Engine项目来服务仅仅一些HTML以及JavaScript。然而,我是基于后台是Python,数据库使用的是Google Cloud Database这一事实来做出决定的。因此利用这个托管前端是有意义的。 24 | 25 | 实现方式非常直接。 26 | 27 | 1. 为前端文件添加一些规则,以及后端的规则全部添加到你的`app.yaml`中。 28 | 2. 创建一个通配符路由到一个处理程序之中,只为`index.html`提供服务。 29 | 3. 在你的通配符之上创建你的API路由从而能够首先匹配。 30 | 31 | ``` 32 | # app.yaml 33 | - url: /assets/(.*) 34 | static_files: dist/assets/\1 35 | upload: dist/assets/.* 36 | 37 | - url: /(.*\.(js|map))$ 38 | static_files: dist/\1 39 | upload: dist/(.*\.(js|map)) 40 | 41 | - url: .* 42 | script: main.app 43 | secure: always 44 | ``` 45 | 46 | ```python 47 | class MainHandler(BaseHandler): 48 | 49 | def get(self, *args, **kwargs): 50 | context = {} 51 | self.response.write(template.render(os.path.join(TEMPLATE_DIR, 'index.html'), context)) 52 | ``` 53 | 54 | 这就是它了!现在开始看第二个 55 | 56 | ## Google App Engine Flex 57 | 58 | 哦,App Engine Flex!听起来酷炫吊炸天。它首先,的确是这样的。 59 | 60 | 我曾经利用Vue.js创建一个叫做[Scrobblin' With Friends](https://scrobblin-friends.appspot.com/)的非常小的SPA,从而能够将Last.fm带回到我的生活中。它是一个简单的app,允许你登录你的Last.fm的用户名,它展示了所有你关注的朋友。它是一个迷你的app,几乎是没有后台的。它所做的所有事情就是拿到一个用户名,大概每隔10秒调用一个API接着展示一些数据。他的确不需要采取一个App Engine项目。 61 | 62 | 然后我发现了Flex,我们发现它们具有一个Node.js环境。它非常容易创建: 63 | 64 | 1. 仅有2行的`app.yml`:`runtime: node.js`以及`env: flex` 65 | 2. 具有`start`脚本的`package.json` 66 | 3. 一个简单的express服务 67 | 68 | ```javascript 69 | // server.js 70 | var express = require('express'); 71 | var app = express(); 72 | 73 | const PORT = process.env.PORT || 8080; 74 | 75 | app.get('/static/*', function(request, response){ 76 | console.log('static file request : ' + request.params[0]); 77 | response.sendFile( __dirname + '/static/' + request.params[0]); 78 | }); 79 | 80 | app.get('*', function(request, response) { 81 | response.sendFile(__dirname + '/index.html'); 82 | }); 83 | 84 | app.listen(PORT); 85 | ``` 86 | 87 | 我很快就完成了配置并且完成了部署,并且运行的很好。直到我这个月收到了我的账单。 88 | 89 | 标准App Engine和Flex环境之间最重要的区别就是在Flex环境中你的项目永远不会消失。在标准环境中,如果没有人访问你的网站,你就不需要支付。即使你占用了一点点流量,它们也很慷慨的对此免费。我没有想到的是,在Flex中就没有免费的午餐了。在我注意到的几天之间,我已经积累了30美元的账单。 90 | 91 | 我认为如果你愿意花足够预算来进行托管的话,那么Flex将会是一个可行的方法。这并不是我所提及的项目之一。因此返回到我曾经使用的标准的App Engine。 92 | 93 | ## 3.now 94 | 95 | 如果你还没有听说过 [now](https://zeit.co/now),那么**现在**你就应该去看一看。它真的很酷。在你的电脑安装之后,你只需要在你的命令行中输入`now`,接着你的应用就可以在web上访问。 96 | 97 | 你只需要提供带有`start`脚本的`package.json`文件。`now`将会帮你完成剩余的工作。 98 | 99 | 就和它所提供的酷的部署过程一样,也有一些我的确不喜欢的方面。 100 | 101 | 1. 免费的版本只能为你的项目提供一些杂乱的URL,例如coolproject-glkqdjsslm.now.sh。通常如果我没有为托管付费的话我介意使用一些奇怪的URL,但是问题每次你部署的时候,你获得一个新的URL,你基本不可能免费托管一个别人能够使用的应用。 102 | 2. 他们的最便宜的付费套餐,为你提供1000次部署每个月(而不是20次),私有的代码库,更多的是14.99美元每个月的。这远远超过了我愿意为那些简单项目提供的预算。 103 | 104 | ## 4. GitHub Pages 105 | 106 | 最终,你看完了我的SPA托管经验中的糟糕经历。我们最终来到了本文的重点,就是我在GitHub Pages上托管SPA的经验。 107 | 108 | 在这上面托管SPA是不是看起来很合理,对不对?你可以获得免费的托管。部署也非常容易,免费的SSL。再加上你的代码可能就要保存在GitHub上! 109 | 110 | 我最近决定是时候替换我的个人网站了,这是一个我几乎没怎么花精力的免费的Wordpress网站(并且最终我用密码保护它因为它令我很尴尬)。我的新网站[http://evansalter.com](http://evansalter.com/),是利用Vue.js开发的并且没有后台,因此我能够选择任何一个托管服务。App Engine(包括标准的以及Flex)都对我来说太昂贵了,`now`也是不可行的,理由我已经在上文中阐述过了。因此在这,我们选择了GitHub Pages。 111 | 112 | 它并不是十全十美的。当然,这可能还有一些问题并且你需要一些方法来避免,但是我没有遇到任何阻拦,并且我确信你也会不会。这么说吧,如果GitHub Pages是一个付费的服务,那么我遇到的一些问题可能让我另投他家。因为它是免费的,所以我愿意花时间来解决这些问题。 113 | 114 | 我希望能够完整阐述整个运转过程,包括在这个过程中我遇到的各种问题。 115 | 116 | ### 第一部分:什么是GitHub Pages? 117 | 118 | 首先,可以看看[这](https://pages.github.com/)。这里面有GitHub Pages所有的基础概念,如果你希望得到更详细的文档你可以点击右上角的“Pages Help"。 119 | 120 | 有两种Pages。第一种是组织/个人page。它们存在于一个叫做`.github.io`的仓库中,并且具有一个匹配仓库名称的URL。这对于一个个人或者组织来说是一个通用的页面。这个网站的代码存在于这个项目之中。 121 | 122 | 另外一种,是一个项目page,大多数存在于`gh-pages`分支中,或者是在一个`master`分支中的`/docs`文件夹中。然后你就可以通过`.github.io/`来访问页面。它允许你在一个地方保存所有的代码。我认为这很方便。(译者注:其实现在可以直接在master分支中直接托管你的page了,可参见我的另外一篇[文章](http://blog.csdn.net/madneal/article/details/53535914)) 123 | 124 | 基于本文的目的,我将主要讨论个人的page。 125 | 126 | ### 第二部分:我的仓库应该是什么样的? 127 | 128 | 这是我遇到的第一个问题。一个个人主页是由`master`分支来提供服务的。那意味着我不能直接利用Vue CLI来创建一个项目,提交所有的代码到master,并且期望它能够运行。 129 | 130 | 在做过一些在线的研究之后,我开始了一个计划。我创建一个`sources`分支来存储源代码文件。接着,在我自己的电脑上,我构建这个项目,将`dist`文件假初始化成一个git仓库,并且让其追踪`master`分支,然后提交以及推送。它运行的很好但是大部分是手工操作的。加上如果我重新克隆这个项目或者使用另外一台电脑的话,我必须再次创建dist仓库。这好麻烦。 131 | 132 | ### 第三部分:自动部署 133 | 134 | 我不打算按照以上的流程来实施,因此我写了一个脚本来帮我做这些,接着通过创建Travis CI来运行它。在网上有很多脚本能够完成这样的功能。当我发现Travis事实上具有一个GitHub Pages部署服务的时候我就开始尝试这个并且将其为我的项目工作。在提交一些代码之后,我最终得到一个相当简单的`.travis.yml`来完成所有任务。 135 | 136 | ```yaml 137 | language: node_js 138 | node_js: 139 | - "node" 140 | script: 141 | - yarn run lint 142 | - yarn run build 143 | deploy: 144 | provider: pages 145 | skip_cleanup: true 146 | github_token: $GITHUB_TOKEN 147 | local_dir: dist 148 | target_branch: master 149 | on: 150 | branch: sources 151 | ``` 152 | 153 | 它基本上会运行我的lint并进行构建,接着如果这个分支是`sources`的话,强制推送`dist`文件夹到`master`。关于此的更多信息,可以参考[Travis CI docs](https://docs.travis-ci.com/user/deployment/pages/)。 154 | 155 | ### 第四部分:路由 156 | 157 | 我们非常平滑的来到这一步骤。我在使用webpack dev server能够迅速地进行本地开发,通过hot module reloading。当我希望部署的时候,我只要推送我的变化然后不久之后这些变动就存在了。我再设置Vue路由就不会遇到任何问题。 158 | 159 | 事实证明,当我是用这个网站的时候我总是从这个网站的根目录开始地。我从来没有直接到`/projects`或者其它地任一page。那时候我遇到一个问题。当我尝试访问我app的一个路由的时候导致了一个404页面。 160 | 161 | 当我发现这一点的时候我一点都不震惊。这很正常,因为GitHub并不知道Vue app的路由。它所知道的所有就是在`index.html`文件中可以路由的路径。 162 | 163 | 我尝试使用两个不同的方案来解决这个问题。取决于你的需求,可能某一个更适合你。 164 | 165 | **尝试一:Hacking这个404页面** 166 | 167 | 我发现网上另外一个人和我一样尝试解决这个问题。你可以参考他的[博客](http://www.backalleycoder.com/2016/05/13/sghpa-the-single-page-app-hack-for-github-pages/)。我承认这确实不是一个好的结局方案但是它也是非常容易实现。直到GitHub提出一个更好的解决方案,这是一个相当好的处理方法。 168 | 169 | 这个解决方案基于你可以使用一个在GH Page上自定义的404页面的事实。所有你需要的做的是在你的仓库中添加一个`404.html`页面。更具上面的链接,我创建了`404.html`并且在``中添加以下内容: 170 | 171 | ```html 172 | 175 | 176 | ``` 177 | 178 | 基本上这个所做的所有事情是在你的浏览器中保存请求的URL,并且加速你返回网站的根目录。很明显,这并不足够。如果某个人点击了这个博客的链接,我将不希望他们重新返回主页。下一步就很简单了。我就是向`index.html`中添加另外一个脚本来检查保存的URL,如果它存在的话就进行重定向操作。 179 | 180 | ```javascript 181 | 190 | ``` 191 | 192 | 着意外地能够工作的很好。然而,一旦我我决定在我的博文中部署Open Graph以及Twitter meta 标签的时候,它没有成功由于这个scrapers没有遵守这个重定向规则。然而,如果你有一个简单的网站并且不需要meta标签的时候,那么这个可能就适合你。 193 | 194 | **尝试二:预渲染一个静态网站** 195 | 196 | 上面的解决方案在服务meta标签中存在着两个问题: 197 | 198 | 1. 当Facebook, Slack, Twitter或者其他具有富媒体的网站会扫描我的链接,他们会和期望中的一样给出一个404页面。然而,他们不会根据我上面分享的方法来重新定向到合适的页面。这是因为GitHub Pages对于404页面返回一个404状态码,这会告诉scraper放弃。 199 | 2. 即使我不使用这个404页面hack,我的meta标签可以在我的Vue app中生成。因为这个scraper在没有执行任何javascript的时候来下载这个页面,它不会找到这些meta标签。 200 | 201 | 因此,另一个明显的解决方案是服务端渲染或者预渲染。我不想直接尝试服务端渲染,因为我不响利用一个服务器来托管这个网站。因此,我们采用了预渲染! 202 | 203 | 因为我使用的是Webpack,我认为通过添加一个webpack插件从我的网站中生成静态的HTML是有意义的。我发现了一些预先构建的插件来完成这个任务,这些都利用PhantomJS来渲染这个网站。因为某些原因,我不能利用它在我的网站中渲染任何内容。我尝试花费大量时间来令它工作,但最后也没有成功。 204 | 205 | 对此感到沮丧,我决定自己写一个插件。因此,[webpack-static-site-generator](https://github.com/esalter-va/webpack-static-site-generator)就诞生了(好名字,我知道)。通过利用这个插件,当我为生产环境进行构建的时候我能为我所有的页面获得静态的HTML文件。我依然能够在本地开发的时候使用Webpack dev server,并不需要构建,这将会是一个很大的优点。 206 | 207 | 因此,如果你在托管你的SPA上遇到任何的问题,你可能想要尝试预渲染。 208 | 209 | ## 第五部分:自定义域名 210 | 211 | 如果你已经走到这一步,那么你应该已经完成在GH Page上托管的种种细节。创建一个自定义域名非常的简单。有以下几个步骤: 212 | 213 | 1. 在你的仓库中创建一个`CNAME`文件,里面包含一行你希望使用的域名(比如`www.evansalter.com`)。确保在构建的时候这个文件已经提交到你的master分支。 214 | 2. 在你的域名注册上创建一个`CNAME`记录指向你的`github.io`地址(比如`esalter-va.github.io`) 215 | 216 | 如果你希望使用顶级域名(没有www)的时候,可能会有细微的不同,但应该不会涉及太多的工作。 217 | 218 | 我发现了一个小问题。就是当你在GH Page上使用自定义域名的时候就没有了SSL支持。我对此感到很烦恼,但是看到我的网站也没有使用HTTPS特别的理由,我也忽略了这一点。 219 | 220 | # 最终的想法 221 | 222 | 当我第一次开始这个网站的时候,我很激动能够利用GitHub Page来托管单页面应用。然而,它并不是看起来的那样神奇。我在这个过程中遇到了很多问题。有一些解决方案比较简单,然而有一些就有一些复杂。然而,我依然乐于解决它并且坚持到了最后。Page的简易性让它很好,我将会建议每个人至少为下一个项目考虑下它。 223 | 224 | -------------------------------------------------------------------------------- /Service worker介绍.md: -------------------------------------------------------------------------------- 1 | # Service worker介绍 2 | 3 | > 原文:[Service workers explained](https://github.com/w3c/ServiceWorker/blob/master/explainer.md) 4 | > 5 | > 译者:[madneal](https://github.com/madneal) 6 | > 7 | > welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | > LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | ## 那么它是什么? 12 | 13 | Service worker正是被开发用于解决web平台上经常出现的问题和疑虑,包括: 14 | 15 | * 无法解释([Extensible Web Manifesto](https://extensiblewebmanifesto.org/) 中)的HTTP缓存以及高级HTTP交互比如HTML5 AppCache。 16 | * 难以自然地构建一个离线优先地web应用。 17 | * 缺乏可以利用很多提出功能的上下文执行。 18 | 19 | 20 | 我们也注意到了声明解决方案([Google Gears](https://gears.google.com), [Dojo Offline](http://www.sitepen.com/blog/category/dojo-offline/)以及[HTML5 AppCache](http://alistapart.com/article/application-cache-is-a-douchebag)都没能实现他们的承诺。每个连续的仅有声明的方法都以相同的方式失败了,所以service worker采取了一个不同的设计方法:一个可以用开发者牢牢把控的重要系统: 21 | 22 | Service worker就好像它的内部有一个有一个[shared worker](https://html.spec.whatwg.org/multipage/workers.html#sharedworker) : 23 | 24 | * 在它自己的全局脚本上下文中运行(通常是在它自己的线程中) 25 | * 不会和特定的页面绑定 26 | * 不能够访问DOM 27 | 28 | 不像shared worker,它: 29 | 30 | * 即使没有页面也能够运行 31 | * 如果不使用的话可以终止,还可以再次运行当需要的时候(比如,他不是事件驱动的) 32 | * 拥有一个定义的升级模式 33 | * 只允许HTTPS(更多的是在这一点上) 34 | 35 | 我们可以利用service workers: 36 | 37 | * 利用网络拦截可以让让网站[更快以及/或者支持离线使用](https://www.youtube.com/watch?v=px-J9Ghvcx4) 38 | * 作为其它'background'功能的基础比如[消息推送](http://updates.html5rocks.com/2015/03/push-notificatons-on-the-open-web)以及[后台同步](https://github.com/slightlyoff/BackgroundSync/blob/master/explainer.md) 39 | 40 | ## 开始 41 | 42 | 首先你需要注册一个service worker: 43 | 44 | ```js 45 | if ('serviceWorker' in navigator) { 46 | navigator.serviceWorker.register('/my-app/sw.js').then(function(reg) { 47 | console.log('Yey!', reg); 48 | }).catch(function(err) { 49 | console.log('Boo!', err); 50 | }); 51 | } 52 | ``` 53 | 54 | 在这个例子中,`/my-app/sw.js`就是service worker脚本的位置,并且它控制那些页面的URL以`/my-app/`开头。 55 | 56 | `.register`返回一个promise。如果你以前没接触过promise的话,可以看看[HTML5Rocks article](http://www.html5rocks.com/en/tutorials/es6/promises/)。 57 | 58 | 一些限制: 59 | 60 | * 注册页面必须安全地提供(没有证书错误的HTTPS) 61 | * service worker和页面必须同源,尽管你可使用 [`importScripts`](https://html.spec.whatwg.org/multipage/workers.html#apis-available-to-workers:dom-workerglobalscope-importscripts)去导入其它地方的脚本 62 | 63 | 64 | * 作为必须的范围 65 | 66 | ### 只有你说HTTPS? 67 | 68 | 使用service worker,你可以劫持请求,进行不同的响应,并且过滤响应。这些功能都很强大。尽管你可以将这些能力用在好的地方,但是中间人可能不会。为了避免这一点,你只能在HTTPS上提供的页面上注册service worker,所以我们知道浏览器接收的service worker没有在网络种没有被篡改。 69 | 70 | Github Pages是由HTTPS提供服务的,所以是一个绝佳的展示demo的地方。 71 | 72 | ## 初始生命周期 73 | 74 | 当你调用`.register`之后,你的service worker会经历三个阶段 75 | 76 | 1. Download 77 | 2. Install 78 | 3. Activate 79 | 80 | 你可以使用事件和`install`以及`activate`进行交互: 81 | 82 | ```js 83 | self.addEventListener('install', function(event) { 84 | event.waitUntil( 85 | fetchStuffAndInitDatabases() 86 | ); 87 | }); 88 | 89 | self.addEventListener('activate', function(event) { 90 | // You're good to go! 91 | }); 92 | ``` 93 | 94 | 你可以向`event.waitUntill`传递一个promise从而来继承这个过程。一旦`activate`事件被触发了,你的service worker就可以控制页面了! 95 | 96 | ## 那么我现在可以控制页面了? 97 | 98 | 额,不完全是。当document浏览时,它会选择一个service worker作为它的控制器,因此你使用`.register`注册的document并不是被控制的,因为那并不是service worker首次加载的地方。 99 | 100 | 如果你刷新document,它将会是在service worker的控制之下。你可以通过`navigator.serviceWorker.controller`来看一下是哪个service worker在进行控制,如果没有的话结果就会是`null`。 101 | 102 | 注意:当你从一个service worker更新到另外一个的时候,可能会有一点点不一点。我们会进入“Updating"阶段。 103 | 104 | 如果使用shift来重载网页的话,加载就会有控制器了,这样做是为了测试CSS以及JS变化。 105 | 106 | Document通常是和一个service worker存在于整个声明周期,或者根本就没有service worker。然而,service worker可以调用`self.skipWaiting()`([spec](https://w3c.github.io/ServiceWorker/#service-worker-global-scope-skipwaiting)) 来立刻接管范围内的所有页面。 107 | 108 | ## 网络截获 109 | 110 | ```js 111 | self.addEventListener('fetch', function(event) { 112 | console.log(event.request); 113 | }); 114 | ``` 115 | 116 | 你可以利用fetch事件: 117 | 118 | * 在你的service worker作用域下浏览 119 | * 任何被这些页面触发的请求,甚至是对其他源的请求 120 | 121 | 这意味着你可以监听所有对于这个页面的请求,CSS,JS,图片,XHR,图标等等所有。 122 | 123 | * iframes & ``--这些将根据它们的资源URL选择其控制器 124 | * Service workers - 对于service worker的fetch/update请求不会通过service worker 125 | * 请求是在service worker之内出发的 - 否则你会获得一个循环 126 | 127 | `request`对象会给你关于这个request的信息,比如它的URL,方法以及头部。但是最有趣的是,他可以劫持请求并且给出不同的响应。 128 | 129 | ```js 130 | self.addEventListener('fetch', function(event) { 131 | event.respondWith(new Response("Hello world!")); 132 | }); 133 | ``` 134 | 135 | [这是一个 demo](https://jakearchibald.github.io/isserviceworkerready/demos/manual-response/). 136 | 137 | `.repondWith`使用一个`Reponse`对象或者一个解析后的promise。上面我们是在创建一个手工的response。这个`Reponse`对象来自于 [Fetch Spec](https://fetch.spec.whatwg.org/#response-class).。在这个规范里面同样也存在着`fetch()`方法,它会返回一个promise作为响应,这意味着你可以在任何地方获取你的响应。 138 | 139 | ```js 140 | self.addEventListener('fetch', function(event) { 141 | if (/\.jpg$/.test(event.request.url)) { 142 | event.respondWith( 143 | fetch('//www.google.co.uk/logos/…3-hp.gif', { 144 | mode: 'no-cors' 145 | }) 146 | ); 147 | } 148 | }); 149 | ``` 150 | 151 | 在上面,我捕获了以`.jpg`结尾的请求并且将Google doodle作为响应。`fetch()`请求默认是 [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing),但是通过设置`no-cors`我可用使用这个响应,即使他不能跨域访问headers(尽管我们不能利用JavaScript访问内容)。[这是demo](https://jakearchibald.github.io/isserviceworkerready/demos/img-rewrite/). 152 | 153 | Promise能够让你从一个方法返回到另外一个方法: 154 | 155 | ```js 156 | self.addEventListener('fetch', function(event) { 157 | event.respondWith( 158 | fetch(event.request).catch(function() { 159 | return new Response("Request failed!"); 160 | }) 161 | ); 162 | }); 163 | ``` 164 | 165 | Service worker是带有一个cache API,使得以后可以方便的存储响应以便重用。不久之后,但是第一点 166 | 167 | ## 更新一个service worker 168 | 169 | Service worker的生命周期是建立在Chrome的更新模型上的:在后台尽可能多地做,不要打扰用户,当当前版本关闭的时候完成更新。 170 | 171 | 无论何时你在你的service worker作用域内浏览页面,浏览器都会在后台检查更新。如果这个脚本是字节不同的,那么它就会被认为是一个新的版本,并且被安装(注意:只有这个脚本被检查,而不是外部的`importScripts`)。然而,老版本的会持续对页面的控制直到所有使用它的tab都被关闭了(除非在install的过程中调用`.replace()`)。接着这个老版本的就会被回收从而新的版本开始接管。 172 | 173 | 这样做是为了避免同时运行两个版本的service worker在不同的tab中。我们当前的策略是: [“cross fingers, hope it doesn’t happen”](https://twitter.com/jaffathecake/status/502779501936652289). 174 | 175 | 注意:更新遵顼header中worker脚本的新鲜度(比如`max-age`),除非`max-age`大于24个小时,否则最多只能保持24个小时。 176 | 177 | 178 | ```js 179 | self.addEventListener('install', function(event) { 180 | // this happens while the old version is still in control 181 | event.waitUntil( 182 | fetchStuffAndInitDatabases() 183 | ); 184 | }); 185 | 186 | self.addEventListener('activate', function(event) { 187 | // the old version is gone now, do what you couldn't 188 | // do while it was still around 189 | event.waitUntil( 190 | schemaMigrationAndCleanup() 191 | ) 192 | }); 193 | ``` 194 | 195 | [下面是实践中的实现](https://www.youtube.com/watch?v=VEshtDMHYyA): 196 | 197 | 不幸的是,刷新一个tab不足够收集到旧的woker兵器让新的进行接管。浏览期在上传当前页面之前向下一个页面发送请求,所以不存在当前active worker被释放。 198 | 199 | 最简单的方法是关闭然后重新打开这个tab(cmd+w,然后cmd+shift+t Mac),或者shift+reload然后就是正常的重新加载了。 200 | 201 | ## 缓存 202 | 203 | Service worker带有一个[caching API](https://w3c.github.io/ServiceWorker/#cache-objects)能够让你产生由请求作为键值的store。 204 | 205 | ```js 206 | self.addEventListener('install', function(event) { 207 | // pre cache a load of stuff: 208 | event.waitUntil( 209 | caches.open('myapp-static-v1').then(function(cache) { 210 | return cache.addAll([ 211 | '/', 212 | '/styles/all.css', 213 | '/styles/imgs/bg.png', 214 | '/scripts/all.js' 215 | ]); 216 | }) 217 | ) 218 | }); 219 | 220 | self.addEventListener('fetch', function(event) { 221 | event.respondWith( 222 | caches.match(event.request).then(function(cachedResponse) { 223 | return cachedResponse || fetch(event.request); 224 | }) 225 | ); 226 | }); 227 | ``` 228 | 229 | 在缓存之内匹配类似于浏览器的缓存。方法,URL以及`vary`header都被考虑在内,但是header的新鲜度被忽略了。缓存的东西只有在你手动移除的时候才生效。 230 | 231 | 你可以通过`cache.put(request, response)`向缓存中添加独立的条目,包括你自己产生的。你也可以控制匹配,[忽略其它的](https://w3c.github.io/ServiceWorker/#cache-query-options-dictionary),比如查询字符串,方法以及vary header。 232 | 233 | ## 其它service worker相关的标准 234 | 235 | 由于service worker可以及时地调动事件,及时未打开页面,也可以在后台偶尔调用其它功能: 236 | 237 | * [Push](http://w3c.github.io/push-api/) 238 | * [Background sync](https://github.com/slightlyoff/BackgroundSync) 239 | * [Geofencing](https://github.com/slightlyoff/Geofencing) 240 | 241 | ## 总结 242 | 243 | 这份文档只是简要地介绍了service worker的能力,并不是售空页面或者service worker实例的所有的可用的API。也不涉及创作,修改以及更新应用程序的service worker。通过这个,希望能够引导你理解service worker中的promise以及对于URL友好的以及可伸缩的默认支持离线使用的web应用的丰富的promise。 244 | 245 | ## Acknowledgments 246 | 247 | Many thanks to [Web Personality of the Year nominee](http://www.ubelly.com/thecritters/) Jake (“B.J.”) Archibald, David Barrett-Kahn, Anne van Kesteren, Michael Nordman, Darin Fisher, Alec Flett, Andrew Betts, Chris Wilson, Aaron Boodman, Dave Herman, Jonas Sicking, Greg Billock, Karol Klepacki, Dan Dascalescu, and Christian Liebel for their comments and contributions to this document and to the discussions that have informed it. 248 | -------------------------------------------------------------------------------- /你真的理解grok吗?.md: -------------------------------------------------------------------------------- 1 | # Do you grok Grok? 2 | 3 | >原文:[Do you grok Grok?](https://www.elastic.co/blog/do-you-grok-grok) 4 | > 5 | >译者:[madneal](https://github.com/madneal) 6 | > 7 | >welcome to star my [articles-translator](https://github.com/madneal/articles-translator/), providing you advanced articles translation. Any suggestion, please issue or contact [me](mailto:bing@stu.ecnu.edu.cn) 8 | > 9 | >LICENSE: [MIT](https://opensource.org/licenses/MIT) 10 | 11 | 12 | > grok (verb) 13 | > 14 | > understand (something) intuitively or by empathy. 15 | 16 | 解析日志数据时最常见的任务是将原始文本行分解为其他工具可以操作的一组结构化字段。 如果你使用 Elastic Stack,则可以利用 Elasticsearch 的聚合和 Kibana 的可视化,从日志中提取的信息(如 IP 地址,时间戳和特定域的数据)解释业务和操作问题。 17 | 18 | 对于 Logstash,这个解构工作由 [logstash-filter-grok](https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html) 来承担,它是一个过滤器插件,可以帮助你描述日志格式的结构。 19 | 20 | [这里有超过200个 grok 模式](https://github.com/logstash-plugins/logstash-patterns-core/tree/master/patterns)对于一些概念进行概括,如[IPv6 地址](https://github.com/logstash-plugins/logstash-patterns-core/blob/v4.0.2/patterns/grok-patterns#L29),[UNIX 路径](https://github.com/logstash-plugins/logstash-patterns-core/blob/v4.0.2/patterns/grok-patterns#L38)和[月份名称](https://github.com/logstash-plugins/logstash-patterns-core/blob/v4.0.2/patterns/grok-patterns#L52)。 21 | 22 | 为了以 grok 库匹配下列一行的格式,只需要将一些模式组合在一起: 23 | 24 | `2016-09-19T18:19:00 [8.8.8.8:prd] DEBUG this is an example log message` 25 | 26 | `%{TIMESTAMP_ISO8601:timestamp} \[%{IPV4:ip};%{WORD:environment}\] %{LOGLEVEL:log_level} %{GREEDYDATA:message}` 27 | 28 | 这样就会生成结构化结果: 29 | 30 | ```{ 31 | { 32 | "timestamp": "2016-09-19T18:19:00", 33 | 34 | "ip": "8.8.8.8", 35 | 36 | "environment": "prd", 37 | 38 | "log_level": "DEBUG", 39 | 40 | "message": "this is an example log message" 41 | 42 | } 43 | 44 | ``` 45 | 46 | 很简单,是不是? 47 | 48 | 是! 49 | 50 | 很棒!就到这了么?不!因为... 51 | 52 | ## “我正在使用 grok 并且它非常慢” 53 | 54 | 这是一个非常普遍的说法!性能是一个经常从社区引发的话题,用户或客户通常会创建一个 grok 表达式,这将极大地减少 logstash 管道每秒处理的事件数量。 55 | 56 | 如前所述,grok 模式是正则表达式,因此这个插件的性能受到正则表达式引擎严重影响。 在接下来的章节中,我们将提供一些关于创建 grok 表达式来匹配日志行的操作指南。 57 | 58 | ## 测量,测量,测量 59 | 60 | 为了在 grok 表达式设计过程中验证决策和实验,我们需要一种方法来快速测量两个或更多表达式之间的性能。 为此,我创建了一个小的 jruby 脚本,它直接使用logstash-filter-grok 插件,绕过 logstash 管道。 61 | 62 | 你可以从[这](https://gist.github.com/jsvd/a2613ea1ba00f02926a302781ca62f7b)获取脚本。我们将使用它来收集性能数据来验证(或者推翻!)我们的假设。 63 | 64 | ## 留意 grok 匹配失败时的性能影响 65 | 66 | 尽管知道 grok 模式与日志条目可以多快匹配非常重要,但是了解它在什么时候匹配失败也很重要。匹配成功和匹配失败的性能可能会差异很大。 67 | 68 | 当 grok 无法匹配一个事件的时候,它将会为这个事件添加一个 tag。默认这个 tag 是 [_grokparsefailure](https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html#plugins-filters-grok-tag_on_failure)。 69 | 70 | Logstash 允许你将这些事件路由到可以统计和检查的地方。 例如,你可以将所有失败的匹配写入文件: 71 | 72 | ```yaml 73 | input { # ... } 74 | filter { 75 | grok { 76 | match => { 77 | "message" => "%{TIMESTAMP_ISO8601:timestamp} [%{IPV4:ip};%{WORD:environment}] %{LOGLEVEL:log_level} %{GREEDYDATA:message}" } 78 | } 79 | } 80 | output { 81 | if "_grokparsefailure" in [tags] { 82 | # write events that didn't match to a file 83 | file { "path" => "/tmp/grok_failures.txt" } 84 | } else { 85 | elasticsearch { } 86 | } 87 | } 88 | ``` 89 | 90 | 如果发现有多个模式匹配失败,则可以对这些行进行基准测试,并找出它们对管道吞吐量的影响。 91 | 92 | 现在我们将使用 grok 表达式来解析 apache 日志行并研究其行为。 首先,我们从一个示例日志条目开始: 93 | 94 | `220.181.108.96 - - [13/Jun/2015:21:14:28 +0000] "GET /blog/geekery/xvfb-firefox.html HTTP/1.1" 200 10975 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"` 95 | 96 | 使用以下 grok 模式来匹配它: 97 | 98 | `%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "%{WORD:verb} %{DATA:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:response:int} (?:-|%{NUMBER:bytes:int}) %{QS:referrer} %{QS:agent}` 99 | 100 | 现在,我们将比较成功匹配的匹配速度和不符合格式的其他三个日志条目,无论是在开始,中间还是在行尾: 101 | 102 | ``` 103 | beginning mismatch - doesn't start with an IPORHOST 104 | 105 | 'tash-scale11x/css/fonts/Roboto-Regular.ttf HTTP/1.1" 200 41820 "http://semicomplete.com/presentations/logs' 106 | 107 | middle mismatch - instead of an HTTP verb like GET or PUT there's the number 111 108 | 109 | '220.181.108.96 - - [13/Jun/2015:21:14:28 +0000] "111 /blog/geekery/xvfb-firefox.html HTTP/1.1" 200 10975 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"' 110 | 111 | end mismatch - the last element isn't a quoted string, but a number 112 | 113 | '220.181.108.96 - - [13/Jun/2015:21:14:28 +0000] "GET /blog/geekery/xvfb-firefox.html HTTP/1.1" 200 10975 "-" 1' 114 | 115 | ``` 116 | 117 | 这些日志行在文章开头提到的脚本进行基准测试,结果如下: 118 | 119 | [![jndER.md.png](https://s1.ax1x.com/2017/12/21/jndER.md.png)](https://imgchr.com/i/jndER) 120 | 121 | 每秒匹配的日志数 122 | 123 | 我们可以看到,对于这个 grok 表达式,取决于不匹配的位置,检查一行不匹配的时间可能比常规(成功)匹配慢6倍。 这有助于解释在行数不匹配时 grok 最大化 CPU 使用率的用户报告,如https://github.com/logstash-plugins/logstash-filter-grok/issues/37。 124 | 125 | 对此我们可以做什么呢? 126 | 127 | ## 设置锚可以提升匹配失败的性能 128 | 129 | 既然现在我们知道匹配失败对你的管道性能是很危险的,我们需要修复它们。 在正则表达式设计中,你可以做的最好的事情来帮助正则表达式引擎是减少它需要做的猜测工作。 这就是为什么通常会避免贪婪模式的原因,但是我们稍微回顾一下,因为有一个更简单的变化来改变模式的匹配。 130 | 131 | 让我们回到我们可爱的 apache 日志行... 132 | 133 | `220.181.108.96 - - [13/Jun/2015:21:14:28 +0000] "GET /blog/geekery/xvfb-firefox.html HTTP/1.1" 200 10975 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"` 134 | 135 | 它由以下的 grok 模式来进行解析: 136 | 137 | `%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "%{WORD:verb} %{DATA:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:response:int} (?:-|%{NUMBER:bytes:int}) %{QS:referrer} %{QS:agent}` 138 | 139 | 由于grok插件的用户的自然期望,隐藏在表面上的性能问题显而易见:假设我们编写的 grok 表达式仅从开始到结束与我们的日志行匹配。 实际上,grok 被告知的是“在一行文本中找到这个元素序列”。 140 | 141 | 等一下,什么?就是它了,“在一行文本中”。这意味着比如一行数据... 142 | 143 | `OMG OMG OMG EXTRA INFORMATION 220.181.108.96 - - [13/Jun/2015:21:14:28 +0000] "GET /blog/geekery/xvfb-firefox.html HTTP/1.1" 200 10975 "-" "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)" OH LOOK EVEN MORE STUFF` 144 | 145 | 将会依然匹配 grok 模式!好消息是修复很简单,我们只需要添加一些锚! 146 | 147 | 锚允许你将正则表达式固定到字符串的某个位置。 通过在我们的 grok 表达式中添加行锚点(^和$)的开始和结束,我们确保我们只会匹配整个字符串从开始到结束,而不包含其他的。 148 | 149 | 这在匹配失败的情况下非常重要。 如果锚点不在位,并且正则表达式引擎不能匹配一行日志,它将开始尝试在初始字符串的子字符串中查找该模式,因此我们在上面看到了性能下降。 150 | 151 | 152 | 因此,为了看到性能影响,我们产生一个新的使用[锚](https://ruby-doc.org/core-1.9.3/Regexp.html#class-Regexp-label-Anchors)的表达式与之前的表达式进行对比: 153 | 154 | `^%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] "%{WORD:verb} %{DATA:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:response:int} (?:-|%{NUMBER:bytes:int}) %{QS:referrer} %{QS:agent}$` 155 | 156 | 下面是结果: 157 | 158 | [![jncKe.md.png](https://s1.ax1x.com/2017/12/21/jncKe.md.png)](https://imgchr.com/i/jncKe) 159 | 160 | 对于不匹配的场景,这是一个相当显著的变化! 不仅我们在中端和末端场景中消除了巨大的性能下降,而且使初始匹配失败检测速度提高了 10 倍左右。 赞。 161 | 162 | ## 留意两次匹配相同的行 163 | 164 | 你可能会说:“好吧,我的所有行都格式正确,所以我们没有匹配失败”,但情况可能并非如此。 165 | 166 | 随着时间的推移,我们已经看到了 grok 用法的一个非常常见的模式,尤其是当来自多个应用程序的日志行通过单个网关(如 syslog)向所有消息添加公共头时。 举一个例子:假设我们有三个使用“common_header:payload”格式的应用程序: 167 | 168 | ``` 169 | Application 1: '8.8.8.8 process-name[666]: a b 1 2 a lot of text at the end' 170 | 171 | Application 2: '8.8.8.8 process-name[667]: a 1 2 3 a lot of text near the end;4' 172 | 173 | Application 3: '8.8.8.8 process-name[421]: a completely different format | 1111' 174 | ``` 175 | 176 | 一个常见的 grok 设置就是在一个 grok 中匹配三种格式: 177 | 178 | ``` 179 | grok { 180 | "match" => { "message => [ 181 | '%{IPORHOST:clientip} %{DATA:process_name}\[%{NUMBER:process_id}\]: %{WORD:word_1} %{WORD:word_2} %{NUMBER:number_1} %{NUMBER:number_2} %{DATA:data}', 182 | '%{IPORHOST:clientip} %{DATA:process_name}\[%{NUMBER:process_id}\]: %{WORD:word_1} %{NUMBER:number_1} %{NUMBER:number_2} %{NUMBER:number_3} %{DATA:data};%{NUMBER:number_4}', 183 | '%{IPORHOST:clientip} %{DATA:process_name}\[%{NUMBER:process_id}\]: %{DATA:data} | %{NUMBER:number}' 184 | ] } 185 | } 186 | ``` 187 | 188 | 现在请注意,即使你的应用程序正确日志记录,grok 仍然会依次尝试将传入日志行与三个表达式进行匹配,从而在第一次匹配时中断。 189 | 190 | 这意味着确保我们尽可能快地跳到正确的位置仍然很重要,因为应用程序2总是有一个失败的匹配,应用程序3有两个失败的匹配。 191 | 192 | 我们经常看到的第一个策略是对Grok匹配进行分层:首先匹配 header,覆盖 message 字段,然后仅匹配 bodies: 193 | 194 | ``` 195 | filter { 196 | grok { 197 | "match" => { "message" => '%{IPORHOST:clientip} %{DATA:process_name}\[%{NUMBER:process_id}\]: %{GREEDYDATA:message}' }, 198 | "overwrite" => "message" 199 | } 200 | grok { 201 | "match" => { "message" => [ 202 | '%{WORD:word_1} %{WORD:word_2} %{NUMBER:number_1} %{NUMBER:number_2} %{GREEDYDATA:data}', 203 | '%{WORD:word_1} %{NUMBER:number_1} %{NUMBER:number_2} %{NUMBER:number_3} %{DATA:data};%{NUMBER:number_4}', 204 | '%{DATA:data} | %{NUMBER:number}' 205 | ] } 206 | } 207 | ) 208 | ``` 209 | 210 | 仅仅这一个就是一个有趣的性能提升,匹配行比初始方法快了2.5倍。 但是如果我们添加我们的同伴锚呢? 211 | 212 | [![jnTxS.md.png](https://s1.ax1x.com/2017/12/21/jnTxS.md.png)](https://imgchr.com/i/jnTxS) 213 | 214 | 有意思!添加锚点使得两个架构的性能同样出色! 事实上,由于失败的匹配性能大大提高,我们最初的单杆设计稍微好一点,因为有一个比较少的匹配正在执行。 215 | 216 | ## 好的,那么我们如何知道事情进行得如何? 217 | 218 | 219 | 我们已经得出结论,监控“_grokparsefaiure”事件的存在是必不可少的,但是你可以做更多的事情: 220 | 221 | 自从版本 3.2.0 grok 插件,已经有很多设置可以帮助你什么时候事件需要花费长时间来匹配(或者失败匹配)。使用[timeout millis 以及 timeout 标签](https://www.elastic.co/guide/en/logstash/5.0/plugins-filters-grok.html#plugins-filters-grok-timeout_millis)能够对于 grok 匹配的时间设置一个上限。如果达到了限制时间,这次匹配就会被中断并且被打上 `_groktimeout` 标签。 222 | 223 | 使用我们之前介绍的相同的条件策略,你·可以将这些事件重定向到 elasticsearch 中的文件或不同的索引,以供日后分析。 224 | 225 | 另一个非常酷的事情,我们将在 Logstash 5.0 中引入度量的上下文是能够提取管道性能的数据,最重要的是,每个插件的统计数据。 在 logstash 运行时,你可以查询其 AP I端点,并查看 logstash 在一个插件上花费的累积时间: 226 | 227 | ``` 228 | $ curl localhost:9600/_node/stats/pipeline?pretty | jq ".pipeline.plugins.filters" 229 | [ 230 | { 231 | "id": "grok_b61938f3833f9f89360b5fba6472be0ad51c3606-2", 232 | "events": { 233 | "duration_in_millis": 7, 234 | "in": 24, 235 | "out": 24 236 | }, 237 | "failures": 24, 238 | "patterns_per_field": { 239 | "message": 1 240 | }, 241 | "name": "grok" 242 | }, 243 | { 244 | "id": "kv_b61938f3833f9f89360b5fba6472be0ad51c3606-3", 245 | "events": { 246 | "duration_in_millis": 2, 247 | "in": 24, 248 | "out": 24 249 | }, 250 | "name": "kv" 251 | } 252 | ] 253 | ``` 254 | 255 | 有了这些信息,你可以看到grok的“duration_in_millis”是否快速增长,如果失败的数量在增加,可以作为警告标志,表明某些模式设计不好,或者消耗的时间比预期的多。 256 | 257 | ## 总结 258 | 259 | 希望这篇博文能够帮助你理解 grok 的行为,以及如何提高吞吐量。 总结我们的结论: 260 | 261 | 1. grok 匹配失败的时候性能可能表现不好。 262 | 2. 监测发生 `_grokfailures`的情况并且对于他们的消耗进行基准测试。 263 | 3. 使用锚比如 `^` 以及`$` 避免歧义并且帮助正则引擎。 264 | 4. 如果你不使用锚的话使用分层匹配会提高性能。如果怀疑的话,直接测量。 265 | 5. 使用超时设置或者即将推出的 Metrics API 能够让你更好地了解 grok 是如何工作的,并且是性能分析的第一点。 266 | --------------------------------------------------------------------------------