カテゴリー
AWS

ReactをS3のSiteHostingで配信する方法

ReactビルドしてS3バケットに配置すればええだけやん。

と、思うやん?

そら(ちゃんとトップページからアクセスして、リンク全部踏んでったら)そう(ええと思うし、あとSPAとかはね、問題ない)よ。

せやけど、リロードとかさ、するやん?人間だもの。

S3にはindex.htmlしかない訳やから、ReactのルーティングでURL(location)が変更されてる状態でリロードしたら、404になる訳なんよね。例えば、”/giants” みたいなルーティングをReactで実現してたとしても、そらそんなディレクトリない訳やから。

そう言う時の話やね。アパッチとかエンジンエックスやったらリライトルールでなんとかするんやけども、S3のhostingん時はどうすんねんって。

ちょっと調べるといろんな解決方法があって、まず一番簡単なのが、errorオブジェクトをindex.htmlにするって言う。

https://stackoverflow.com/questions/51218979/react-router-doesnt-work-in-aws-s3-bucket

最初見た時は何や天才やん。と思ったよね。

これならだいたいindex.htmlにルーティングされるから、意図したReactのルーティングになる。確かに。せやけど。これ、確かに、動き的にはええんやけど、実際は、HTTPステータスが404のまま動いてる感じなんよね。

なんかちょっと気持ち悪いかなって。

次見つけたの。

出たわね。

これもうすごい。ルーティングをハッシュ付きのやつに置き換えてくって言う作戦。確かに、これならindex.htmlで全部処理できるからね。天才アンド天才。すごい。

React側のコードにも手を入れる必要があるので、お手軽さで言えば最初の方なんやけども、こっちは綺麗に解決できる感がある。

なんてすごいんだ……(恍惚

カテゴリー
AWS

AWSのクライアントVPNエンドポイントを使ってみる

なんやVPNって全然わからんで…。

せやからAWSを使ってやってみるンゴねぇ…。

まずは、なんでVPNかって話なんやけども、AWSに作ったVPCの中身にプライベートにしたいっちゅうことやね。ほんなら、VPCにVPNで繋いだったらええやんってことらしいで。

ネット上によくあるVPNの説明図見てると、確かに、どこかを経由してどこかに繋がるみたいな、そんな感じやね。
その経由するところを、AWSやとクライアントVPNエンドポイントっちゅうのを利用して実現できるみたいや。

わい <=> クライアントVPNエンドポイント <=> VPC

的な話やな。ほんまにできるんやろか…。

まずは、普通にVPCを作って。

次に、クライアントVPNエンドポイント作ってみるで。

クライアント IPv4 CIDRってなんやねん…

VPCのCIDRとルートが重複しなければいいらしい。としか書いてないんやが…、適当でよさそう…、ほんまに?

次にサーバー証明書がいるみたい…。どないすんのこれ。

普通にCertificateManagerで証明書を作るか認証局を建てるか、どこかで作った証明書をインストールするかみたいなことらしい。

そこで、どうやらec2で自前の認証局を作ったらいいみたいなことがどこかに書いてあった。

その通りにしてみる。

おもむろにAmazon Linux2を起動して、こいつに認証局として動作してもらうで。

手順はこ↑こ↓を参考に。「OpenVPNの設定」の前までやって、サーバー用とクライアント用の鍵っぽいのを集める。

https://qiita.com/kapioz/items/5b75c3470a4e57d916ba

ca、サーバー用のcert、サーバー用のkeyを用意して、Certificate Managerで証明書のインポートを行う。

こ↑こ↓

証明書本文 : cert
証明書のプライベートキー : key
証明書チェーン : ca

ちな、リージョンに注意。

これが終わったら、クライアントVPNエンドポイントの作成に戻ろう。

認証オプションに相互認証を指定して、サーバー証明書 ARN*、クライアント証明書 ARN*、どちらにも先ほどインポートした証明書のARNを指定する。

できたら、このエンドポイントを接続したいサブネットにアタッチする。セキュリティグループを設定し、認証タブで、接続を許可するIPアドレスをCIDR表記で指定する。

これで準備完了。

クライアント設定のダウンロードでクライアント VPN エンドポイントの VPN クライアント設定ファイルをダウンロードし、↑で作っておいたクライアント用のcertとkeyを追記する。

これで、VPN接続ができるようになる。

ようわからんが、TunnelblickっちゅうのがMacやと鉄板なんかな?そいつに設定ファイルをポイーで、VPN接続に成功したで…!

なお、VPNに接続した状態でインターネットに出ていけるようにするには、別途設定が必要の模様や。ルートテーブルで0.0.0.0/0を外に出ていけるサブネットにターゲットしたらええんやな。

が、プライベートなところにアクセスできればいいのであればこれで充分みたいや。確かに、プライベートなIPでさっきのインスタンスとかにも接続できたし。できてる。VPNできてるで。

もう、SSHで踏み台してとかいう時代じゃ無いんか、もしかして…?

カテゴリー
Laravel

Mailableのプレビュー時、Markdownのテンプレートで@component()なHTMLがエスケープされてしまうンゴ

Mailableを実装したものは、簡単にプレビューできるようになっとる。例えば、こんな感じにルーティングする。

Route::get('mailable', function () {
    return (new ClassImplementsMailable)
        ->subject('foobar')
        ->markdown('emails.foobar', []);
});

そうすると、メールの中身がどんなふうに組み立てられるかを確認することができる。

今回は、Auth関連のユーザー登録時にメールアドレス検証のために送信されるメールの内容を調整したかった。いろいろいじりたかったので、Mailableを実装したクラスに置き換える。

vendor/laravel/framework/src/Illuminate/Auth/Notifications/VerifyEmail.php
を継承したクラスのtoMail()をこんな感じにする。


    /**
     * Build the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable);
        }

        return (new ClassImplementsMailable)
           ->markdown(); // ここでいろいろ

returnが\Illuminate\Notifications\Messages\MailMessageとなっているのでtoMail()の呼び出し元を見てみる。

    /**
     * Send the given notification.
     *
     * @param  mixed  $notifiable
     * @param  \Illuminate\Notifications\Notification  $notification
     * @return void
     */
    public function send($notifiable, Notification $notification)
    {
        $message = $notification->toMail($notifiable);

        if (! $notifiable->routeNotificationFor('mail', $notification) &&
            ! $message instanceof Mailable) {
            return;
        }

        if ($message instanceof Mailable) {
            return $message->send($this->mailer);
        }

        $this->mailer->send(
            $this->buildView($message),
            array_merge($message->data(), $this->additionalMessageData($notification)),
            $this->messageBuilder($notifiable, $notification, $message)
        );

インスタンスがMailableだった場合の処理も用意されてるので、問題無い。きっと。

ここで、件のメール内容のプレビューの話に戻る。

というわけでまずは、元々使われていたMarkdownのテンプレートをベースに調整しようとしたのだが…。

出たわね。

テンプレートはこう。

@component('mail::message')
    {{-- Greeting --}}
    @if (! empty($greeting))
        # {{ $greeting }}
    @else
        @if ($level === 'error')
            # @lang('Whoops!')
        @else
            # @lang('Hello!')
        @endif
    @endif

    {{-- Intro Lines --}}
    @foreach ($introLines as $line)
        {{ $line }}

    @endforeach

    {{-- Action Button --}}
    @isset($actionText)
        <?php
        switch ($level) {
            case 'success':
            case 'error':
                $color = $level;
                break;
            default:
                $color = 'primary';
        }
        ?>
        @component('mail::button', ['url' => $actionUrl, 'color' => $color])
            {{ $actionText }}
        @endcomponent
    @endisset

    {{-- Outro Lines --}}
    @foreach ($outroLines as $line)
        {{ $line }}

    @endforeach

    {{-- Salutation --}}
    @if (! empty($salutation))
        {{ $salutation }}
    @else
        @lang('Regards'),<br>{{ config('app.name') }}
    @endif

    {{-- Subcopy --}}
    @isset($actionText)
        @component('mail::subcopy')
            @lang(
                "If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
                'into your web browser: [:actionURL](:actionURL)',
                [
                    'actionText' => $actionText,
                    'actionURL' => $actionUrl,
                ]
            )
        @endcomponent
    @endisset
@endcomponent

どうやら、@componentの中身がエスケープされて表示されてしまっている模様。

調べたところ、Laravelの特定のバージョンで起こるとかなんとか。みなさん、いろいろ試行錯誤していたようだが、結果、解決策は…。

@component('mail::message')
{{-- Greeting --}}
@if (! empty($greeting))
# {{ $greeting }}
@else
@if ($level === 'error')
# @lang('Whoops!')
@else
# @lang('Hello!')
@endif
@endif

{{-- Intro Lines --}}
@foreach ($introLines as $line)
{{ $line }}

@endforeach

{{-- Action Button --}}
@isset($actionText)
<?php
switch ($level) {
case 'success':
case 'error':
$color = $level;
break;
default:
$color = 'primary';
}
?>
@component('mail::button', ['url' => $actionUrl, 'color' => $color])
{{ $actionText }}
@endcomponent
@endisset

{{-- Outro Lines --}}
@foreach ($outroLines as $line)
{{ $line }}

@endforeach

{{-- Salutation --}}
@if (! empty($salutation))
{{ $salutation }}
@else
@lang('Regards'),<br>{{ config('app.name') }}
@endif

{{-- Subcopy --}}
@isset($actionText)
@component('mail::subcopy')
@lang(
"If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
'into your web browser: [:actionURL](:actionURL)',
[
'actionText' => $actionText,
'actionURL' => $actionUrl,
]
)
@endcomponent
@endisset
@endcomponent

インデントを消す。

ええやん。

おそらく最新のLaravelやとおこらないと思うんやけども、いつかのために。ちなみにバージョンはv5.7.28やった。

カテゴリー
Laravel

compact(): Undefined variable: operator っていうエラーがでたンゴ

過去のLaravelを新しい環境で動かしてみたら件のエラーが出たンゴ。Laravelは5.4。新しい環境のPHPは7.4。

QueryBuilderの処理で上記例外が発生している模様。

 /**
     * Add an exists clause to the query.
     *
     * @param  \Illuminate\Database\Query\Builder $query
     * @param  string  $boolean
     * @param  bool  $not
     * @return $this
     */
    public function addWhereExistsQuery(self $query, $boolean = 'and', $not = false)
    {
        $type = $not ? 'NotExists' : 'Exists';

        $this->wheres[] = compact('type', 'operator', 'query', 'boolean');

        $this->addBinding($query->getBindings(), 'where');

        return $this;
    }

こ↑こ↓

PHPが7.1にダウングレードするか、Laravelのバージョンを上げる必要がありそう。

なので、このエラーに直面したらPHPのバージョンの問題の可能性が微レ存っていう話。