Node.js セキュリティアップデート + Node.js v15 について

# Node.js セキュリティアップデートが出てた

[https://nodejs.org/en/](https://nodejs.org/en/)

2.23 に、Node.js の新しいバージョンがでたのでチェックしよう。
[https://nodejs.org/en/blog/vulnerability/february-2021-security-releases/](https://nodejs.org/en/blog/vulnerability/february-2021-security-releases/)

### 10.x, 12.x, 14.x 15.x 用のセキュリティアップデート

重大(1), 高い深刻度(1), 低い深刻度(1)

1. HTTP/2 の unknownProtocol があまりにも多くなった時、DoS 攻撃を受ける可能性がある問題
    - ファイルシステムが漏洩する可能性
    - メモリリークを引き起こす可能性
2. localhost6 がホワイトリストに含まれている場合、DoS 攻撃を受ける可能性がある問題
    - /etc/hosts に localhost6 を含んでいる場合、この攻撃を受ける可能性がある
    [https://jvndb.jvn.jp/ja/contents/2018/JVNDB-2018-005401.html](https://jvndb.jvn.jp/ja/contents/2018/JVNDB-2018-005401.html)
3. OpenSSL の脆弱性が Node.js を介して悪用される可能性がある問題

適宜追従しましょう（フロントエンドだけなら別にって感じだけど）。

※**Nodejs 10.x は 2021.4.30 にサポート終了予定**、12.x 系は 2022.4.30 で終了予定
※奇数バージョンは機能開発用バージョンで、偶数バージョンは長期サポートバージョン。最新 15.x 以外の奇数はない

### Node.js のバグ報告について

nodejs-sec グループ
[https://groups.google.com/g/nodejs-sec?pli=1](https://groups.google.com/g/nodejs-sec?pli=1)

バグ報告の方法
[https://github.com/nodejs/node/blob/master/SECURITY.md](https://github.com/nodejs/node/blob/master/SECURITY.md)

Nodejs にバグを報告するとお金もらえるプログラム：バグバウンティプログラム
[https://hackerone.com/nodejs](https://hackerone.com/nodejs)




---

# Node.js v15 について

Node.js v15 あまりキャッチアップしてなかったので、おさらいしてみました。

[https://nodejs.org/en/](https://nodejs.org/en/)

v15 のリリースは 2020.10.21。v16 は 2021.4 とかですかね。


公式 Medium
[https://nodejs.medium.com/node-js-v15-0-0-is-here-deb00750f278](https://nodejs.medium.com/node-js-v15-0-0-is-here-deb00750f278)

codedamn さんのまとめ YouTube
[https://www.youtube.com/watch?v=OIzGI5wFiXg](https://www.youtube.com/watch?v=OIzGI5wFiXg)

めっちゃまとまってる
[https://shisama.hatenablog.com/entry/2020/10/21/004612](https://shisama.hatenablog.com/entry/2020/10/21/004612)

# 1. npm 7 が同梱

npm 7 が入った。

[https://www.npmjs.com/package/npm](https://www.npmjs.com/package/npm)

- `workspace` という概念が入った
    - monorepo で作りたい時とかは便利そう
- `acceptDependencies` という概念も入った
- `peerDependencies` の挙動変更
- `npx` が実行前に確認されるようになった
- `npm audit` の表示方法が変更
- `package.exports` が npm の内部モジュールを参照できないようになった
- `npm test` の表示内容が変更
- `npm build` と `npm unbuild` が廃止

[https://blog.watilde.com/2020/10/14/npm-v7の主な変更点まとめ/](https://blog.watilde.com/2020/10/14/npm-v7%E3%81%AE%E4%B8%BB%E3%81%AA%E5%A4%89%E6%9B%B4%E7%82%B9%E3%81%BE%E3%81%A8%E3%82%81/)

# 2. unhandledRejection の挙動変更

ブレイキングチェンジ！ 

- `unhandledRejection` の挙動が変わった。default `warn` だったのが `throw` になった。

ただそもそもこれが起きてる時は以下のタイミングで

- `Promise` を使った非同期処理において想定外のエラーが起きた
- エラーハンドリングが漏れている
- 単純なコードのエラー

マズイプログラムになっているはずなので、挙動が変更になることでより安全なコードが書けるようになった。

[https://zenn.dev/kimamula/articles/b32d11d52c2b7a733119](https://zenn.dev/kimamula/articles/b32d11d52c2b7a733119)

## unhandledRejection について

[https://medium.com/@hagevvashi/unhandledrejectionについて-70739d2b6a60](https://medium.com/@hagevvashi/unhandledrejection%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-70739d2b6a60)

Web サービスを運営していると、Sentry を使ってエラーハンドリングしたりすると思う

[https://sentry.io/welcome/](https://sentry.io/welcome/)

`window.onerror` は、`Promise.reject()` によって投げられたエラーは拾わない
（ただし `console.error()` 形式で表示はされる）

`Promise` を使うエラー（Node.js でファイル操作だとかをするときの I/O 処理や、ブラウザで API 通信の失敗）を検知する時に使う。

```javascript
try {
  await axios.post("/some-resources");
} catch(e) {
  // error handling
  throw e; // this causes unhandled rejection
}
```

```javascript
window.addEventListener("unhandledrejection", (e: PromiseRejectionEvent): void => {
  // an error loginng
  logError(e.reason);
});
```

```javascript
process.on("unhandledRejection", (error: {} | null | undefined, promise: Promise<any>) => {
  // an error loging
  logError(error);
})
```

[https://medium.com/@hagevvashi/unhandledrejectionについて-70739d2b6a60](https://medium.com/@hagevvashi/unhandledrejection%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-70739d2b6a60)

# 3. ES2021 に対応

JavaScript エンジンの V8 が v8.6 にアップデート。まぁでもブラウザでは既に使えるので珍しくはない

## Promise.any

`Promise.all` は、全部が `resolved` になった時 / どれかが `rejected` になった時エラー

```javascript
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'foo');
});

Promise.all([promise1, promise2, promise3])
  .then((values) => {
    console.log(values);
  })
  .catch(() => {
    console.log("error");
  });
// expected output: Array [3, 42, "foo"]
```

`Promise.race` は、どれかが `resolved` になった時 / どれかが `rejected` になった時エラー
`Promise.allSettled` は、全部が `resolved` か `rejected` になった時 / エラーにはならない
`Promise.any` は、どれかが `resolved` になった時 / 全部が `rejected` になった時エラー

10 個の `Promise` を走らせて、9 個失敗しても、最後の 1 つが成功なら成功としたい時(`race` だとどれかが `reject` になるとエラーになっちゃう)に使う

## WeakRefs

Garbage Collection 時に破棄できるオブジェクトを作れる。

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef)

```javascript
var ref = new WeakRef(element)
ref.deref() // 参照元を取り出す
```

簡単にサンプルを作ってみた。↓
[https://playcode.io/740665/](https://playcode.io/740665/)

タイマーが動き続けている。別のタイマーで DOM 要素を 5 秒後に `remove` する。元のタイマー関数では参照はできている。Garbage Collection されると参照がきえて止まる。

メモリリークを防ぐコードが書ける。

## AggregateError

複数のエラーをまとめたい時に使う。

```javascript
try {
  throw new AggregateError([
    new Error("some error"),
  ], 'Hello');
} catch (e) {
  console.log(e instanceof AggregateError); // true
  console.log(e.message);                   // "Hello"
  console.log(e.name);                      // "AggregateError"
  console.log(e.errors);                    // [ Error: "some error" ]
}
```

エラーを配列で与えられる。

## Logical Assignment Operators 論理代入演算子

読みにくくなるからやめてほしいw

```javascript
let a = true
a &&= false　// x && (x = y): x と y が true な値の場合、y の値が代入される
// false
a
// false
a ||= true　// x || (x = y): x が false な値の場合、y の値が代入される
// true
a
// true
a = null
a ??= 1　// x ?? (x = y): x が null or undefined な値の場合、y の値が代入される
// 1
a
// 1
a ??= 2
// 1
a
// 1
```

## Numeric separators

桁が読みやすくなるから積極的に使おう。

```javascript
123 === 1_2_3
// true
1_000_000_000.000_001
// 1000000000.000001
```

ただこんなでかいマジックナンバー扱いたくないし扱う機会もない気がする。

## String.prototype.replaceAll

ブラウザで使えるようになってたやつ。

[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll)
[https://caniuse.com/mdn-javascript_builtins_string_replaceall](https://caniuse.com/mdn-javascript_builtins_string_replaceall)

IE 11 は Babel を通せば `replaceAll` が書かれたコードはトランスパイルしてくれる。`preset-env (core-js)` を使うことで IE11 でも動く。

[https://v8.dev/features/string-replaceall](https://v8.dev/features/string-replaceall)

ちなみに Next.js は `@babel/preset-env` 入ってないので IE11 対応させるなら `config` で指定する。

# 4. Web Crypto API

JavaScript で暗号化・復号・署名・検証ができる Web 標準 API。

[https://caniuse.com/cryptography](https://caniuse.com/cryptography)

ブラウザでは昔っから使えたやつ。
Node は最近ブラウザで使えたやつが使えるようになってきているといういい話。

# 5. AbortController

Web リクエストを中止することができるグローバルユーティリティオブジェクトの `AbortController` が Node.js 15 でも使えるようになった。

```javascript
const ac = new AbortController();
ac.signal.addEventListener('abort', () => console.log('Aborted!'),
{ once: true });
ac.abort();
console.log(ac.signal.aborted);  // Prints True
```

動画のダウンロードを中止する例

[https://developer.mozilla.org/en-US/docs/Web/API/AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)

```javascript
var controller = new AbortController();
var signal = controller.signal;

var downloadBtn = document.querySelector('.download');
var abortBtn = document.querySelector('.abort');

downloadBtn.addEventListener('click', fetchVideo);

abortBtn.addEventListener('click', function() {
  controller.abort();
  console.log('Download aborted');
});

function fetchVideo() {
  ...
  fetch(url, {signal}).then(function(response) {
    ...
  }).catch(function(e) {
    reports.textContent = 'Download error: ' + e.message;
  })
}
```

`fetch` はまだ Node.js に実装されてないけどね。

フロントエンドの UI 開発で、ボタンに対しての mousedown/mouseup イベントを addEventListen していて、クリック後画面遷移してしまうので removeEventListen しておきたい時、abortController を使えば一発で解除できるテクがどっかで紹介された。

# 6. Event Target

ブラウザで使えた `EventTarget` が Node.js でも使えるようになった。`Event` の発行・伝播はブラウザでは `EventTarget`、Node.js では `EventEmitter` を使っていた。

[https://nodejs.org/api/events.html#events_eventtarget_and_event_api](https://nodejs.org/api/events.html#events_eventtarget_and_event_api)

```javascript
const target = new EventTarget();

target.addEventListener("foo", (event) => {
  console.log("foo is called");
});

const ev = new Event("foo");
target.dispatchEvent(ev);
```

イベントが DOM ツリーを伝って伝播が行われないなど差はあるが、ユニバーサルなプログラムが書けるようになってきている。

# 7. N-API updated

Node.js のネイティブ拡張をするための Node API (通称 N-API) がアップデート。C 言語のインターフェース。まぁ使うことはあまりないのかなぁ。

[https://nodejs.org/api/n-api.html#n_api_node_api](https://nodejs.org/api/n-api.html#n_api_node_api)

# 8. QUIC (実験的機能)

UDP ベースの通信プロトコル「QUIC」が使用できるようになった。
TLS 1.3 ベースでのセキュリティ、フロー制御、エラー訂正、接続、多重化とかとか。

TLS 1.3 とは: [https://kinsta.com/jp/blog/tls-1-3/](https://kinsta.com/jp/blog/tls-1-3/)

HTTP/3 サーバーを作ることができる。
[https://blog.leko.jp/post/http-over-quic-on-nodejs15/](https://blog.leko.jp/post/http-over-quic-on-nodejs15/)

むずすぎてよくわからんですね

# かんそう

- せめて Node.js 14.x にはしとこう