NETWORK ENGINEER BLOG

Tips and Reviews for Engineers

STP の概要

STP とは

STP(Spanning Tree)は、 冗長経路によるループを検出し、フレームの送受信を停止させることにより、ループフリーのネットワークを形成する機能です。

  • IEEE 802.1d として標準化
  • Configuration BPDU と呼ばれるフレームを使用して、Topology 情報を共有する。
  • Root Bridge を起点とする Active Topology と呼ばれる Tree Topology を構成する。

詳細が知りたい場合は、「スパニングツリーの概要 | ネットワークエンジニアの小学校」がわかりやすく、おすすめです。

Active Topology の形成と維持

  • BPDU の優劣に応じて、Root Bridge / Forwarding / Blocking ポート等を決定する。
  • 機器及び、リンク故障時の切替えには、約30~50秒要する。
正常時

f:id:FriendsNow:20210223180611p:plain

故障時

f:id:FriendsNow:20210223180842p:plain

BPDU について

BPDU(Bridge Protocol Data Unit)は、Active Topology の作成、維持、管理を行うためのフレームで以下の特徴があります。

  • スイッチ間でデフォルトでは、2秒間隔で送信、交換
  • BPDU には 「Configuration BPDU」 と「Topology Change Notification BPDU」の 2 種類が存在
BPDU のフォーマット

f:id:FriendsNow:20210223181532p:plain

参考書籍

その他参考

以上

VLAN の概要

VLAN とは

VLAN(Virtual LAN)とは、スイッチ内でブロードキャストドメインを分割する機能で、主な利点は以下の 2つです。

  • 異なる VLAN 間の通信はできなくなり、セキュリティの向上が図れる。
  • ブロードキャストドメインを狭めることで、帯域を有効活用できる。

図にすると、次のような感じです。
VLAN10 や VLAN20 の「数字」は、VLAN ID と呼ばれる識別番号です。
f:id:FriendsNow:20210223151733p:plain

VLAN10 に設定したポートにはいってきたフレームは、同じく VLAN10 を設定したポートにしか転送されません。
Cisco で GE0/1 を VLAN10 に指定する場合は、次のように設定します。

Switch#configure terminal
Switch(config)#interface gigabitethernet0/1
Switch# (config-if)#switchport mode access
Switch# (config-if)#switchport access vlan 10

VLAN トランクとは

  • 複数の VLAN トラフィックを1つの物理リンク上で伝送する技術
  • Cisco は、IEEE 標準の「802.1q」と Cisco 独自仕様の 「ISL(Inter-Switch Link)」をサポート
  • 802.1q 及び ISL は、それぞれ、タグと呼ばれる識別子をフレームに挿入し、複数の VLAN データを 1つのリンクで送受信できるようにします。


f:id:FriendsNow:20210223164835p:plain

Cisco で GE0/24 をトランクポート(VLAN10,20)に指定する場合は、次のように設定します。

Switch#configure terminal
Switch(config)#interface gigabitethernet0/24
Switch# (config-if)#switchport mode trunk
Switch# (config-if)#switchport trunk allowed vlan 10,20

参考書籍

その他参考

以上

はてなブログでよく使うシンタックスハイライト

ブログを書く時に使っているシンタックスハイライトの覚書です。

シンタックスハイライトとは

可読性を上げるため、ソースコードを色付けして表示する機能です。

はてな記法とシンタックスハイライト

はてなブログでシンタックスハイライトを使用するためには、スーパー pre 記法で先頭の >|| の 2本のパイプ(||)の間に指定します。

シンタックスハイライトの使用例

で書かれたソースコードの場合、以下のように html と書きます。

>|html|
<html>
<head>
<title>NETWORK ENGINEER BLOG</title>
</head>

次のようにハイライトされます。

<html>
<head>
<title>NETWORK ENGINEER BLOG</title>
</head>

よく使うハイライト

  • config :Cisco などの Config 関連
  • sh :Linux などの Shell 関連
  • ps1 :PowerShell 関連
  • python :Python 関連
  • yaml :YAML 関連
  • html :HTML 関連
  • sql :SQL 関連

おまけ

余談ですが、はてなブログでソースコードの一部(configなど) を表示する場合は、以下のようにHTML の code タグを使用しています。

-<code>config</code>

すごくめんどくさいので、簡単にかける方法があれば教えてください。。

参考書籍

以上

HTML の基本について

HTML とは

HyperText Markup Language(ハイパーテキスト マークアップ ランゲージ)は、ハイパーテキストを記述するためのマークアップ言語の 1 つ。略して HTML(エイチティーエムエル)と呼ばれることが多い。…(中略)…フォントや文字色の指定などの見た目の指定、などといった機能がある。
出典:フリー百科事典『ウィキペディア(Wikipedia)』

ちょっと何言ってるか分からない。ハイパーテキスト」って何だろう。

ハイパーテキストとは

ハイパーテキスト (hypertext) とは、複数の文書(テキスト)を相互に関連付け、結び付ける仕組みである。「テキストを超える」という意味から"hyper-"(~を超えた) "text"(文書)と名付けられた。テキスト間を結びつける参照のことをハイパーリンクと言う。…(中略)…最も有名なハイパーテキストの実装は World Wide Web である。
出典:フリー百科事典『ウィキペディア(Wikipedia)』

一言でいうと HTML は Web ページを書くための言語ということみたいです。

HTML の書き方

文章を「タグ」と呼ばれるもので囲って(マークアップ=目印をつけて)書いていきます。
なんでものびる WEB さんの説明がわかりやすかったので、引用させて頂きます。

f:id:FriendsNow:20210221060219p:plain:w600
出典:なんでものびる WEB

上記のように、開始タグ <>と 終了タグ </> で囲って書いていきます。
囲まれた文章は、「<タグの名前>要素」と呼ばれます。

主な HTML タグについて

<html></html>:HTML 文書であることを宣言
<head></head>:文書のヘッダを指定
<title></title>:文書のタイトルを指定
<body></body>:文書の本文を指定
<p></p>:段落を指定
<h1~6></h1~6>:文書の見出しを指定(h1 が最も大きく、h6 が最も小さい)

f:id:FriendsNow:20210221062855p:plain:w400
出典:なんでものびる WEB

他にも様々なタグがあります。以下は HTML5 のタグの一例です。詳細はこちら
<img></img>:画像からファイルを読み込む
<strong></strong>:文字を太字にする。
<a></a>:ハイパーリンクを指定※
※アンカータグとよばれ、以下のように記述します。

<a href="sample.html" title="これはリンクです" target="_blank">

HTML の例

上記の HTML タグを使った例です。

<html>
<head>
<title>NETWORK ENGINEER BLOG</title>
</head>
<body>
<h1>HTML の書き方</h1>
<h2>主な HTML タグについて</h2>
<p>HTML タグには、たくさん種類があります。</p>
<p>アンカータグを使えば、<a href=https://friendsnow.hatenablog.com/ target=”_blank”>リンク</a>を挿入することもできます。
</body>
</html>

上記のソースコードを HTML でみると以下(右側)のように表示されます。
f:id:FriendsNow:20210221073937p:plain

以上

定期的なパスワード変更が不要になった理由

「いまだに、定期的にパスワード変更を求めるサービスが結構あるね。」という話を、CSIRT 業務経験のある妻に話したところ、「(パスワード)盗難対策として、必要だからじゃない?」という回答だったので、結構前に不要になった話をしました。
とても驚いていたので、ドヤ顔で講釈をはじめたのですが、うっとおしがられて聞いてもらえなかったので、こちらに書きます。

総務省の方針転換

過去、パスワードを盗難対策として、「定期的なパスワード変更は必要」とされていたのですが、2018年3月に総務省が「不要」と方針転換を発表しました。
簡単にいうと、「パスワードを定期的に変更すると、単純なものを設定したり、使いまわしたりしがちであるから」というのが理由です。

なお、利用するサービスによっては、パスワードを定期的に変更することを求められることもありますが、実際にパスワードを破られアカウントが乗っ取られたり、サービス側から流出した事実がなければ、パスワードを変更する必要はありません。むしろ定期的な変更をすることで、パスワードの作り方がパターン化し簡単なものになることや、使い回しをするようになることの方が問題となります。定期的に変更するよりも、機器やサービスの間で使い回しのない、固有のパスワードを設定することが求められます。

これまでは、パスワードの定期的な変更が推奨されていましたが、2017年に、米国国立標準技術研究所(NIST)からガイドラインとして、サービスを提供する側がパスワードの定期的な変更を要求すべきではない旨が示されたところです*1。また、日本においても、内閣サイバーセキュリティセンター(NISC)から、パスワードを定期変更する必要はなく、流出時に速やかに変更する旨が示されています*2
出典:総務省

逆に言えば、複雑なパスワードを使いまわさず設定するなら、「盗まれても利用される期間が短くなる」といった観点で考えても、有効な対策かもしれません。

パスワードは複雑なものを推奨

定期的に変更するよりも、推測されにい長くて複雑なパスワードの設定が推奨されています。
最近は、コンピューターの処理性能が飛躍的に向上したため、攻撃者は短時間で多くのパスワードを試行できます。*3
また、どれだけ長くて複雑にしても、今後さらにコンピューターの性能が向上した場合に解析される恐れがあるので、試行回数の制限や、二要素認証はしっかりと実装しておく必要があります。

参考書籍

以上

*1:NIST SP800-63B(電子的認証に関するガイドライン)

*2:https://www.nisc.go.jp/security-site/handbook/index.html

*3:いわゆる総当たり攻撃やパスワードリスト攻撃

息子の難病と仕事の変化

お題「#この1年の変化」

振り返りを兼ねて、書いてみます。

息子がクローン病と診断

息子が 3 歳の時、「潰瘍性大腸炎」と診断され、漢方治療で 4 年ほど症状が治まっていましたが、徐々に容体が悪化し、昨年7月に再検査をした結果、「クローン病」と診断されました。
クローン病と潰瘍性大腸炎は、慢性の炎症性腸疾患の一つであり、腹痛や下痢、発熱といった症状を伴います。
大きな違いは、潰瘍性大腸炎は大腸だけに炎症が起こりますが、 クローン病は消化管のどの位置にも炎症を起こす可能性があります。
最初の治療は、エレンタールと呼ばれる総合栄養剤以外は絶食(4週間)という過酷なものでした。
入院中、「食べたい食べたい」と泣きじゃくる息子の姿は、今でも脳裏に鮮明に焼き付いています。
食事再開後も、炎症が再発するなど、しばらく辛い状況が続きましたが、今はレミケードというお薬を定期的に点滴することで、寛解を維持することができています。
先生やスタッフの皆様には、なんとお礼を申し上げてよいのか・・感謝の言葉もありません。
また、食事にはものすごく気をつけなくてはならないため、毎日試行錯誤しながら料理を作ってくれている妻に感謝しています。
f:id:FriendsNow:20210211173652j:plain

テレワーク中心の生活

COVID-19 の影響で、テレワークが中心となりました。
コミュニケーションは、ビデオ会議や、チャットツールがメインとなり、意思疎通が図りづらい日々が続いています。
姿が見えないことへの不安はもちろん、表情や言葉で得られる情報は多かったのだと痛感しています。
f:id:FriendsNow:20210211174851j:plain
一方で、通勤時間が減った分、時間を確保できて、ブログを書いたり、子供と遊ぶ時間が増えたという側面もありました。
息子の影響で、ポケモンカードゲームをはじめたのですが、今では自分が夢中になってしまい、大人の財力で箱買いして、大人げなく全力で戦っています。(でもなぜか負け越しています。奥が深いゲームです。。)

気持ちの変化

息子の闘病生活において、笑顔を支えてくれたのが、ポケモンカードやニンテンドースイッチなどのエンタメでした。
以前から興味はありましたが、息子の影響でより強くなり、これまでインフラ一筋の仕事をしてきましたが、今のエンタメ系コンテンツ開発の仕事に踏み出すきっかけとなりました。
自分もできるだけ多くの人へ笑顔を届けられるような、そんなコンテンツを開発できればと思っています。
また、これまで培ったインフラの知識を、少しづつにはなりますが、はてなブログで共有し、恩返しができればと思います。

以上です。ここまで読んで頂きありがとうございました。

openSUSE Tumbleweed の XRDP で画面が真っ黒になる

Windows 10 から、openSUSE Tumbleweed に XRDP で接続した際、以下のように、画面が真っ黒になる問題に遭遇しました。
f:id:FriendsNow:20210209230038p:plain

原因は「同じユーザーで、ローカル接続していること」でした。
以下のコマンドで、対象ユーザーの全プロセスを kill すると解決しました。

hostname:~# killall -u USERNAME

参考書籍

以上

Windows 10 から openSUSE Tumbleweed に XRDP 接続

openSUSE ソフトウェアで「XRDP」を検索し、openSUSE Tumbleweed の「1クリックインストール」をクリックしてインストールします。f:id:FriendsNow:20210209224315p:plain

XRDP 接続設定

XRDP を有効化

hostname:~# sudo systemctl enable xrdp

XRDP を起動

hostname:~# sudo systemctl start xrdp

Firewall ポート許可

hostname:~# sudo firewall-cmd --add-port=3389/tcp --permanent

Firewall 再起動

hostname:~# sudo firewall-cmd --reload

接続方法

RDP 接続すると、XRDP が起動するので、Session に「Xvnc」に指定し、 ユーザー名とパスワードを入力後、「OK」をクリックします。
f:id:FriendsNow:20210209225307p:plain

XRDP で接続可能となります。
f:id:FriendsNow:20210209225317p:plain

参考書籍

以上

はてなブログに Google アナリティクス 4 プロパティを設定

はてなブログに Google アナリティクス 4 プロパティ(GA4)を設定する方法です。

Google アナリティクス 4 プロパティとは

Google アナリティクス 4 プロパティ(GA4)はアプリ計測ツール「Google アナリティクス For Firebase」の仕組みを土台として、データ構造から再設計された新しい Google アナリティクスです。2019年に発表された「アプリ+ウェブ プロパティ」が、正式に2020年10月に β 版から名称を「Google アナリティクス 4 プロパティ(GA4)」へ変えてリリースされました。
…(中略)…
Google アナリティクス 4 プロパティはプロパティの中に「データストリーム」という新しい概念が追加されました。データストリームは「ウェブ」「iOS」「Android」とそれぞれのデータストリームに分かれています。
ウェブは「GTM か gtag.js で新しい計測 ID をウェブサイトへ追加」することでGA4プロパティの「ウェブストリーム」にデータを収集することができ、iOS、Android は「Firebase プロジェクト」と Google アナリティクス 4 プロパティを連携することで「アプリストリーム」にデータを収集することができます。
f:id:FriendsNow:20210131223009p:plain:w650
出典:アユダンテ株式会社

はてなブログ設定方法

  • GA4 に接続して、左ペインの「管理」➡「データストリーム」をクリックします。
  • グローバルサイトタグ(gstag.js)をコピーして、はてなブログの「設定」➡「詳細設定」の「head に要素を追加」に貼り付けます。

f:id:FriendsNow:20210116175124p:plain

しばらく経過すると、測定結果が反映されます。
f:id:FriendsNow:20210131232301p:plain

以上

デュプレックス(duplex)について

全二重(Full-duplex) 半二重(Half-duplex)とは

  • 半二重モードでは、送信と受信を片方向ずつ、時間を分けて通信する。
    • 100BASE-TX の場合、送信と受信あわせて、最大100Mbps の通信が可能。
  • 全二重モードでは、送信と受信を両方向同時に通信する。
    • 100BASE-TX の場合、送信と受信それぞれ最大 100Mbps の通信が可能。
  • HUB は CSMA/CD 方式である半二重モードのみをサポートしており、送受信を同時に行えない。

f:id:FriendsNow:20210223132049p:plain

オートネゴシエーションについて

  • FLP(Fast Link Pulse)バーストと呼ばれるパルス信号を使用し、互いの通信速度とモードを検出する。
  • 相互の通信モードによっては、リンクダウンや、半二重通信になってしまう場合があるので、注意すること。

f:id:FriendsNow:20210124221424p:plain:w550

デュプレックスミスマッチについて

対向でデュプレックスがあっていない場合、デュプレックスミスマッチとなり、通信が正常にできない場合があります。
Cisco の場合は、CDP が有効になっていると、以下のエラーが出力されます。

%CDP-4-DUPLEX_MISMATCH: duplex mismatch discovered on FastEthernet0/1 (not full duplex), with R1 Ethernet0/0 (full duplex).

上記の表の「〇」となるように、対向の設定をあわせることが対策となります。

以上

Amazon RDS のパラメータ変更について

Amazon RDS(MySQL)において、パラメータグループを変更する際、以下のエラーが発生しました。

保存中のエラー: Cannot modify a default parameter group. (Service: AmazonRDS; Status Code: 400; Error Code: InvalidParameterValue; Request ID: xxxx-xxxx-xxxx-xxxx; Proxy: null)

原因は「デフォルトのパラメータグループの変更しようとしたこと」でした。
仕様上、デフォルトのパラメータグループは、変更不可のようです。
対策は、パラメータグループの作成になります。

パラメータグループの作成

パラメータグループを作成します。作成したパラメータグループは、設定変更が可能です。
f:id:FriendsNow:20210124121740p:plain

パラメータグループの適用

パラメータグループをデータベースに割り当てます。
f:id:FriendsNow:20210124121723p:plain

参考書籍

以上

Amazon RDS(MySQL)で名前解決を無効化

MySQL における名前解決について

MySQL において名前解決は、コネクションの確立・認証のフェーズで利用されます。デフォルト(名前解決が有効)な場合のシーケンスはざっくりと以下のようになります。

  1. IPアドレスが MySQL 内の名前解決キャッシュに載っているかどうかを確認する
  2. (載っていない場合)IP アドレスからホスト名に逆引きをかける(getnameinfo)
  3. 得られたホスト名を正引きし、IP アドレスを得る(getaddrinfo)
  4. IP アドレスとホスト名の両方を使って、接続元ホストの検証をする
  5. 検証に成功した場合、これ以降の「接続元ホスト」は IP アドレスまたはホスト名の「検証に成功したどちらか一方」を利用する
  6. ユーザー名、パスワードなどの認証に進む

名前解決が無効(skip-name-resolve オプションが有効)な場合、上記 1、2、3 のフェーズがスキップされ、4 で検証される対象は IP アドレスのみとなります。
出典:gihyo.jp

Amazon RDS の名前解決無効化

Amazon RDS(MySQL)のデフォルトの設定では、名前解決が有効(skip-name-resolve オプションが無効)となっています。
名前解決を無効化するは、パラメータグループで skip-name-resolve オプションの値を「0」から「1」に変更します。
f:id:FriendsNow:20210124003648p:plain

参考書籍

以上

Amazon RDS(MySQL)構築手順について

Amazon RDS とは

Amazon RDS(Amazon Relational Database Service)とは、その名称のとおり AWS のリレーショナル型のデータベースです。
Amazon RDS では、データベースのインストールやバックアップなどのセットアップをしなくても、データベースが利用できる環境が提供されているため、契約後すぐに AWS 上でデータベースを使用することができます。
出典:NTT 東日本

リレーショナル型データベースとは

リレーショナル型データベース(関係性データベース)とは、行と列の2つの軸で表されるデータベースのことです。イメージとしては、高機能な Excel のようなものです。
データベースは、特定の条件に基づいて複数のデータを管理し、必要に応じて目的のデータを検索したり、編集を行ったりするために必須です。なかでもリレーショナル型データベースは、情報の整合性や管理の効率化に優れているという特徴があります。
以上のことからリレーショナル型データベースは、顧客リスト、商品一覧データ、従業員リストなど幅広い種類のデータ管理に適しています。
出典:NTT 東日本

MySQL 構築例

本例では、インターネットからの接続を想定した場合に、ポイントとなる部分を抜粋しています。他の設定値はデフォルトを使用しています。
「データベースの作成」をクリックします。
f:id:FriendsNow:20210123212407p:plain

「標準作成」➡「MySQL」をクリックします。
f:id:FriendsNow:20210123213321p:plain

インターネットから、データーベースに直接接続する場合、「パブリックアクセス可能」を「あり」に設定します。
f:id:FriendsNow:20210123214027p:plain

「データベースポート」を「3306」に設定します。
f:id:FriendsNow:20210123214114p:plain

「最初のデータベース名」を設定し、「データベースの作成」をクリックします。
f:id:FriendsNow:20210123214157p:plain

データーベース作成後、「接続とセキュリティ」➡「VPC セキュリティグループ」をクリックします。
※外部から接続する「エンドポイント」を控えておきます。
f:id:FriendsNow:20210123215328p:plain

「インバウンドルールを編集」から、許可するグローバル IP を設定します。本例では、インターネットに接続したテスト端末の IP を設定します。
f:id:FriendsNow:20210123214600p:plain
設定は、以上です。

接続テスト

テスト端末に MySQL Workbench をインストールし、「Hostname」に「エンドポイント」を設定して「OK」をクリックします。
f:id:FriendsNow:20210123220140p:plain

以下のように接続できます。
f:id:FriendsNow:20210123220315p:plain

Python の mysql.connector.connect でも接続をテストしてみます。

> vi mysql.py
conn = mysql.connector.connect(
    host='HOSTNAME',
    port='3306',
    user='admin',
    password='PASSWORD',
    database='labdb'
)

print(conn.is_connected())

conn.close()

以下のように接続できます。

> python3 mysql.py
True

参考書籍

以上

Web Application に GA4 を実装する

Firebase で作成した Web Application に GA4(Google Analytics 4)を適用する手順について、ちょっとハマってしまったのでメモです。
Firebase web code lab で作成した Web アプリケーションに、以下のように、Index.html に SDK を読み込むように設定したのですが、機能しませんでした。*1

<!-- Import and configure the Firebase SDK -->
<!-- These scripts are made available when the app is served or deployed on Firebase Hosting -->
<!-- If you do not want to serve/host your project using Firebase Hosting see https://firebase.google.com/docs/web/setup -->
<script src="/__/firebase/8.2.1/firebase-analytics.js"></script>
<script src="/__/firebase/init.js"></script>
<script src="scripts/main.js"></script>

調べたところ、以下の記事に答えがありました。ありがとうございます。

【重要】アップデートされたGoogle Analytics 4にはトラッキングIDが存在しない【2020年10月以降ブログを始める方は要注意】
出典:静かに暮らしたい

Google Analytics 4 にイベントデータを送信するための API(gtag.js)を <head> の先頭に埋め込む必要があるようです。
f:id:FriendsNow:20210116175124p:plain

詳細は以下をご参照ください。
developers.google.com

以上

*1:設定は、こちらを参考にしました。

Firebase web codelab について

はじめに

Firebase でチャットアプリを作成するチュートリアル(Firebase web codelab)を試してみました。
チュートリアルでは、以下のことが学べます。

  • Cloud Firestore と Cloud Storage のデータ同期
  • Firebase Authentication のユーザー認証
  • Web アプリケーションのデプロイ
  • Firebase Cloud Messaging の通知送信
  • Web アプリケーションのパフォーマンスデータ収集

環境

・Firebase 8.2.1
・openSUSE Tumbleweed 20201229
・Virtual Machine:2vCPU, 4GB Memory, 40GB Disk
・VMware(R) Workstation 15 Pro

事前準備

root ユーザー移行

sudo su -

git インストール

zypper install git

npm インストール

zypper install npm

サンプルコードの入手

codelab のリポジトリを複製

git clone https://github.com/firebase/codelab-friendlychat-web

Firebase プロジェクト作成

Firebase にログインして、プロジェクトを作成します。
f:id:FriendsNow:20210101233700p:plain

Firebase Authentication の設定

ウェブアイコン をクリックして、Firebase Web アプリを作成します。
f:id:FriendsNow:20210101233914p:plain

左ペインの「Authentication」➡「Sign-in method」で「Google」をクリックして、有効化します。
f:id:FriendsNow:20210101235629p:plain

Google Cloud Console で OAuth 同意画面を設定します。*1
f:id:FriendsNow:20210102000111p:plain

Cloud Firestore の設定

左ペインの「Cloud FIrestore」から「データベース作成」をクリックして「テストモード」を有効化します。
f:id:FriendsNow:20210102000734p:plain

Firebase CLI インストール

CLI インストール

sudo su -
npm -g install firebase-tools

インストール確認

cd /home/hatkobelab/codelab-friendlychat-web/web-start/
firebase --version

Firebase CLI 承認

firebase login

※CLI をインストールした OS 上で実行する必要があります。それ以外の場合は、localhost に接続できずエラーとなります。本例では、以下のように openSUSE で実行しました。
f:id:FriendsNow:20210102001319p:plain

アプリと Firebase プロジェクトを紐づけ

firebase use --add
? Which project do you want to add? friendlychat-46e4f
? What alias do you want to use for this project? (e.g. staging) default

アプリをローカルで実行

アプリを実行

firebase serve --only hosting

※上述と同様に OS 上で実行します。

ブラウザから http://localhost:5000 に接続
f:id:FriendsNow:20210102001635p:plain
アプリの UI が接続されますが、認証がとおっていないため、まだ機能しません。

ユーザーサインイン設定

チュートリアルでは、Google サインインでユーザー認証するためのコードが用意されているので、対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。

関数:signIn

// Signs-in Friendly Chat.
function signIn() {
  // Sign into Firebase using popup auth & Google as the identity provider.
  var provider = new firebase.auth.GoogleAuthProvider();
  firebase.auth().signInWithPopup(provider);
}

関数:signOut

// Signs-out of Friendly Chat.
function signOut() {
  // Sign out of Firebase.
  firebase.auth().signOut();
}

関数:initFirebaseAuth

// Initiate Firebase Auth.
function initFirebaseAuth() {
  // Listen to auth state changes.
  firebase.auth().onAuthStateChanged(authStateObserver);
}

関数:getProfilePicUrl

// Returns the signed-in user's profile pic URL.
function getProfilePicUrl() {
  return firebase.auth().currentUser.photoURL || '/images/profile_placeholder.png';
}

関数:getUserName

// Returns the signed-in user's display name.
function getUserName() {
  return firebase.auth().currentUser.displayName;
}

関数:isUserSignedIn

// Returns true if a user is signed-in.
function isUserSignedIn() {
  return !!firebase.auth().currentUser;
}

サインインのテストは、上述と同様に OS 上で実行します。

firebase serve --only hosting

以下のように Google でサインインができるようになります。
f:id:FriendsNow:20210102002202p:plain

メッセージの書き込み設定

アプリケーションの UI にデータ入力ができるように Cloud Firestore にデータを書き込みます。ユーザーが作成したメッセージは、Cloud Firestore に保存されます。
チュートリアルでは、ユーザーが「Send」ボタンをクリックすると、データベースに保存するコードが用意されているので、対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。

関数:saveMessage

// Saves a new message to your Cloud Firestore database.
function saveMessage(messageText) {
  // Add a new message entry to the database.
  return firebase.firestore().collection('messages').add({
    name: getUserName(),
    text: messageText,
    profilePicUrl: getProfilePicUrl(),
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
  }).catch(function(error) {
    console.error('Error writing new message to database', error);
  });
}

ブラウザから http://localhost:5000 に接続し「hello」などのメッセージを入力して「Send」ボタンをクリックすると、Firebase コンソールでメッセージを確認できます。
f:id:FriendsNow:20210102182214p:plain

メッセージの読み取り設定

アプリケーションでメッセージを読み取り、表示させます。
データベース内のメッセージが更新された際に、新しいメッセージをアプリケーションに表示させるように対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。

関数:loadMessages

// Loads chat messages history and listens for upcoming ones.
function loadMessages() {
  // Create the query to load the last 12 messages and listen for new ones.
  var query = firebase.firestore()
                  .collection('messages')
                  .orderBy('timestamp', 'desc')
                  .limit(12);
  
  // Start listening to the query.
  query.onSnapshot(function(snapshot) {
    snapshot.docChanges().forEach(function(change) {
      if (change.type === 'removed') {
        deleteMessage(change.doc.id);
      } else {
        var message = change.doc.data();
        displayMessage(change.doc.id, message.timestamp, message.name,
                       message.text, message.profilePicUrl, message.imageUrl);
      }
    });
  });
}

画像送信設定

画像を共有する機能を追加します。
Cloud Firestore は、構造化データの保存に適していますが、Cloud Storage はファイルの保存に適しています。
ユーザーがアプリケーションを使用して共有する画像を Cloud Storage に保存するように対象の関数を置き換えます。ファイルは web-start/public/scripts/main.js です。

関数:saveImageMessage

// Saves a new message containing an image in Firebase.
// This first saves the image in Firebase storage.
function saveImageMessage(file) {
  // 1 - We add a message with a loading icon that will get updated with the shared image.
  firebase.firestore().collection('messages').add({
    name: getUserName(),
    imageUrl: LOADING_IMAGE_URL,
    profilePicUrl: getProfilePicUrl(),
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
  }).then(function(messageRef) {
    // 2 - Upload the image to Cloud Storage.
    var filePath = firebase.auth().currentUser.uid + '/' + messageRef.id + '/' + file.name;
    return firebase.storage().ref(filePath).put(file).then(function(fileSnapshot) {
      // 3 - Generate a public URL for the file.
      return fileSnapshot.ref.getDownloadURL().then((url) => {
        // 4 - Update the chat message placeholder with the image's URL.
        return messageRef.update({
          imageUrl: url,
          storageUri: fileSnapshot.metadata.fullPath
        });
      });
    });
  }).catch(function(error) {
    console.error('There was an error uploading a file to Cloud Storage:', error);
  });
}

ブラウザから http://localhost:5000 に接続し「hello」などのメッセージを入力して「Send」ボタンをクリックすると、アプリケーションに表示されます。また、画像をアプリケーションにアップロードすることもできます。
f:id:FriendsNow:20210102221928p:plain

パフォーマンスデータ収集

Performance Monitoring SDK を使用して、アプリケーションからパフォーマンスデータを収集し、Firebase コンソールでデータの確認および分析ができます。

自動トレースの設定

アプリケーション利用時に自動的にパフォーマンスデータ監視を行うためには、main.js に以下を追加します。

// TODO: Initialize Firebase Performance Monitoring.
firebase.performance();

パフォーマンスデータの表示

Firebase コンソールからパフォーマンスデータを確認できます。通常は、この後の手順で実施するデプロイ後、12時間以内に表示されます。
f:id:FriendsNow:20210102223620p:plain

アプリケーションのデプロイ

Firebase Hosting を使用してアプリケーションを Firebase プロジェクトにデプロイします。
コマンドは以下を使用します。

> cd /home/hatkobelab/codelab-friendlychat-web/web-start/
> firebase deploy --except functions

デプロイ後、Firebase Hosting の URL(以下の2つの Firebase 独自サブドメイン)から、ウェブアプリケーションにアクセスできるようになります。

https://<firebase-projectId>.firebaseapp.com
https://<firebase-projectId>.web.app

f:id:FriendsNow:20210102225510p:plain

通知設定

Firebase Cloud Messaging を使用して、ウェブアプリに通知を配信することができます。

送信者 ID 許可

アプリケーション側で、通知を許可する送信 ID を設定する必要があります。 web-start/public/manifest.jsongcm_sender_id で設定します。※固定値で変更できません。

{
  "name": "Friendly Chat",
  "short_name": "Friendly Chat",
  "start_url": "/index.html",
  "display": "standalone",
  "orientation": "portrait",
  "gcm_sender_id": "103953800507"
}

Service Worker の追加

通知をアプリケーションに表示させるために必要な Service Worker を追加します。 web-start/public ディレクトリに irebase-messaging-sw.js という名前のファイルを作成して、以下のコンテンツを追加します。*2

// Import and configure the Firebase SDK
// These scripts are made available when the app is served or deployed on Firebase Hosting
// If you do not want to serve/host your project using Firebase Hosting see https://firebase.google.com/docs/web/setup
importScripts('/__/firebase/8.2.1/firebase-app.js');
importScripts('/__/firebase/8.2.1/firebase-messaging.js');
importScripts('/__/firebase/init.js');

firebase.messaging();

デバイストークンの取得

デバイスまたはブラウザで通知が有効になると、デバイストークンが提供されます。
ユーザーがサインインすると、ブラウザからデバイストークンを取得し、Cloud Firestore に保存するように設定します。ファイルは web-start/public/scripts/main.js です。

// Saves the messaging device token to the datastore.
function saveMessagingDeviceToken() {
  firebase.messaging().getToken().then(function(currentToken) {
    if (currentToken) {
      console.log('Got FCM device token:', currentToken);
      // Saving the Device Token to the datastore.
      firebase.firestore().collection('fcmTokens').doc(currentToken)
          .set({uid: firebase.auth().currentUser.uid});
    } else {
      // Need to request permissions to show notifications.
      requestNotificationsPermissions();
    }
  }).catch(function(error){
    console.error('Unable to get messaging token.', error);
  });
}

通知権限のリクエスト

ユーザーに通知許可を求めるダイアログをブラウザに表示させます。ユーザーで許可していない場合、デバイストークンは提供されません。

// Requests permission to show notifications.
function requestNotificationsPermissions() {
  console.log('Requesting notifications permission...');
  firebase.messaging().requestPermission().then(function() {
    // Notification permission granted.
    saveMessagingDeviceToken();
  }).catch(function(error) {
    console.error('Unable to get permission to notify.', error);
  });
}

サインイン後、通知許可ダイアログが表示されます。
f:id:FriendsNow:20210102234510p:plain
「許可」をクリックすると、ブラウザの JavaScript コンソールに次のメッセージが表示されます。

Got FCM device token: cWL6w:APA91bHP...4jDPL_A-wPP06GJp1OuekTaTZI5K2Tu

ブラウザに通知を送信

デバイストークンと、サーバーキーを設定し、次の cURL コマンドを実行します。
サーバーキーは、Firebase コンソール から「プロジェクトの概要」➡「プロジェクトを設定」➡「Cloud Messaging」 で確認できます。

curl -H "Content-Type: application/json" \
     -H "Authorization: key=YOUR_SERVER_KEY" \
     -d '{
           "notification": {
             "title": "New chat message!",
             "body": "There is a new message in FriendlyChat",
             "icon": "/images/profile_placeholder.png",
             "click_action": "http://localhost:5000"
           },
           "to": "YOUR_DEVICE_TOKEN"
         }' \
     https://fcm.googleapis.com/fcm/send

アプリケーションがバックグラウンドにある場合、次のようにブラウザに通知が表示されます。
f:id:FriendsNow:20210102235944p:plain

以上

*1:ロゴのアップロードが必須なので注意

*2:8.2.1 は Firebase のバージョンで最新化が必要です。最新のバージョンはこちら