write ahead log

ロールフォワード用

Next.jsで作った静的サイトをGitHubActionsで自動デプロイしたい

サーバーはsshでrsyncできればどこでも良いが、シンフリーサーバーを使った。

フリーじゃなくても使い勝手よさそうなので、必要なら有料版使おうと思う。

プロジェクトの用意

以下のコマンドでSSGのサイトがout/へ出力されるようにしておく。

npm run build

デプロイサーバーのsshキーを登録する

リポジトリ > Settings > Secrets and Variables > Actions のSecretsタブからNew repository secret でssh秘密鍵を登録する。

ここでは「DEPLOY_SERVER_KEY」として登録した。

GitHub Actionsの設定ファイルでは以下で参照できる。

${{ secrets.DEPLOY_SERVER_KEY }}

デプロイサーバーの情報を登録する

リポジトリ > Settings > Secrets and Variables > Actions のVariablesタブからNew repository variable でssh接続に使う情報を登録する

ここでは以下を登録した。

KEY名 内容
DEPLOY_DIR デプロイ先ディレクトリ
DEPLOY_HOST_NAME デプロイ先のホスト名
DEPLOY_HOST_USER_NAME SSHのユーザー名
DEPLOY_SSH_PORT SSHのポート

GitHub Actionsの設定ファイルでは以下のように参照できる。

${{ vars.DEPLOY_SSH_PORT }}

GitHub Actionsの設定

以下へ設定ファイルを書く。

.github/workflows/cicd.yml

こんな感じ。

name: ci/cd
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  ci:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [20.x]
    steps:
      # 実行環境にソースコードを取り込む
      - uses: actions/checkout@v4
      # 実行環境に対してNode.jsのセットアップをする
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          # Node.jsのバージョンを指定
          node-version: ${{ matrix.node-version }}
      # プロジェクトの依存関係をインストール
      - name: Install dependencies
        run: npm install
      # lint実行
      - name: Lint code
        run: npm run lint
      # prettier実行
      - name: format code
        run: npm run fmt
  cd:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [20.x]
    steps:
      # 実行環境にソースコードを取り込む
      - uses: actions/checkout@v4
      # 実行環境に対してNode.jsのセットアップをする
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          # Node.jsのバージョンを指定
          node-version: ${{ matrix.node-version }}
      # プロジェクトの依存関係をインストール
      - name: Install dependencies
        run: npm install
      # ビルド
      - name: Build code
        run: npm run build
      # sshキーを配置
      - name: ssh key generate
        run: echo "$SSH_PRIVATE_KEY" > key && chmod 600 key
        env:
          SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SERVER_KEY }}
      - name: deploy
        run: rsync -auzr -e "ssh -i key -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p ${{ vars.DEPLOY_SSH_PORT }}" --delete ./out/* ${{ vars.DEPLOY_HOST_USER_NAME }}@${{ vars.DEPLOY_HOST_NAME }}:${{ vars.DEPLOY_DIR }}

まとめと参考ページ

ちょっと手間取ったがやはり楽になる。

PHPで多要素認証(Google Authenticator)したい

既存のPHPアプリに多要素認証を加えたいという話もボチボチあったりして、時代を感じる。

ググるとすぐに出るのは以下のライブラリなんだけど、PHP7までしか対応していない。

プルリクエストも考えたがすでにある感じだし、ちょっと使うのは無理かなと思った。

github.com

困ったなと手軽に使えそうなものをusのGoogleで探していると以下が出てきた。

github.com

使い方

そういうわけで使ってみたのでちょっとメモしておく。

まずcomposerで入れる。

composer require pragmarx/google2fa

次にQRコードに含めるキーを作成して、そのあとにQRコードへ表示するデータURLを生成してやる。

use PragmaRX\Google2FA\Google2FA;
    
$google2fa = new Google2FA();
    
$secret = $google2fa->generateSecretKey();

// $secretはDBなどに保存する

$qrTitle = '多要素認証アプリに表示するタイトル。システム名など';
$accountName = '多要素認証アプリに表示するアカウント名';
$qrCodeUrl = $google2fa->getQRCodeUrl(
    $qrTitle
    $accountName,
    $secret
);

// $qrCodeUrlを表示側へ返す

あとは返したQRコード用のURLを表示してやればよいのですが、QRコードはブラウザで生成してもらうことにしました。

davidshimjs.github.io

サンプルコードの通りこんな感じで書くだけで大丈夫です。

<div id="qrcode"></div>
<script type="text/javascript">
new QRCode(document.getElementById("qrcode"), "【サーバーから来たQRコード用データURL】");
</script>

これをGoogleAuthenticatorのようなアプリで読み取ります。

表示された認証コードをサーバーへ再びPOSTして認証するのは以下のようなコードでOK。

$code = 【POSTされたコード】;

$valid = $google2fa->verifyKey("【保存しておいたsecret】", $code);
// trueかfalse

結構簡単に使えてよかったです。

Electronで外部アプリを起動するコードを書きたかった

ただ外部アプリを呼び出したいだけなのにやたらと苦労したのでメモ。

Windowsでnode14という限定的な状況だったのでたぶんもう使うことはなさそうだけど、供養として。

const app = [electronのapp];
const exepath = [exeへのフルパス];

// 外部アプリを実行
const child = child_process.spawn(exepath, []);

// 起動に失敗したらerrorイベントが起きる
child.on('error', (error) => {
  console.log(`起動失敗[${exepath}](${error.message})`);
  app.quit();
});

// 実行したアプリが終わったらexitが起きる
child.on('exit', (code) => {
  console.log('アプリ終了');
  app.quit();
});

// 起動に成功したらプロセス番号が割り当てられてる
if (child.pid) {
  console.log(`アプリ起動成功[${exepath}]`);
}

WebPushで通知を実装する時に助かったページ

ブックマークが膨れ上がったからここに置いとく。

試したけど仕事で使うのはやめといた。

subscriptionの有効期限の更新方法とかが微妙にわからん。

そもそもPWA自体が利用者側になじみがないので、toCでなくてもちょっと説明がムズイ。

どのサイトもありがたかったです。とりあえずどれか1つ試せば動かせる感じ。

iOSのSafariでバッジ付けたかったのでこれを探した。

ちゃんと読めてないけど、つまみ食いでも大枠の理解に助かった。

iOSのinput選択したらズームされてしまうを避けたい

そのままの記事があった。ありがたい。

trust bank - iOSのinputとtextareaクリック時にズームされてしまうのを防ぐ

こんな感じで「maximum-scale="1.0"」で対応できるらしい。へー。

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"/>

Vue3とVue-router4でガードかけたい

なんか適当にググっても欲しい日本語の記事が出てこないので書いとく。

というか公式読めば書いてあるからだとは思うんだけど。

これをやればよいだけなので。

Vue-Router - Global injections within guards

viteで作成したプロジェクトをベースにした。

main.jsを変更する

まず、refとprovide用のkeyをimportした。

で、routerをuseする前にapp.provideで設定しただけ。

import { createApp, ref } from 'vue'
import App from './App.vue'
import router from './router'
import { authCodeKey } from '@/injectKeys.js'

const app = createApp(App)

const authCode = ref(null)
app.provide(authCodeKey, authCode)

app.use(router)

app.mount('#app')

router/index.jsを変更する

グローバルガードを書いた。

router.beforeEach((to, from) => {
  const authCode = inject(authCodeKey)

  if (to.name !== 'login' && (!authCode || authCode.value === null)) {
    return { name: 'login' }
  }
})

export default router