<![CDATA[ゆるっとエンジニアブログ]]>https://jikoblog.netlify.app/https://jikoblog.netlify.app/favicon.pngゆるっとエンジニアブログhttps://jikoblog.netlify.app/Ghost 2.9Mon, 18 Sep 2023 00:15:13 GMT60<![CDATA[Box CLI でページ割りを使用する]]>https://jikoblog.netlify.app/get-trashed-items-with-marker-pageination-using-boxcli/Ghost__Post__65075b878ed63100015115fbSun, 17 Sep 2023 23:53:57 GMTBox CLI でページ割りを使用する

Box CLI では、listコマンド(例: box users:listなど、:list部分は省略可)を使用することでオブジェクト(ユーザーなど)の一覧を取得することができますが、上限が1000となっており、またページ割り機能も未実装のようなので(執筆時点)、1000件を超える場合は全部のデータが取得できないようです(関連Issue)。
そこで、listコマンドを使用せずにbox requestコマンドでページ割りを行って1000件以上ある場合でも、全部のデータを取得するスクリプトを作成しました。内容を以下に記載します。

利用環境

以下の環境を使用しました

  • Box CLI: ver 3.1.0(バージョン依存しないと思いますが、一応記載)
  • OS: Windows 10
  • Powershell: 5.1.19041.3031

MacOSおよびLinuxでも、pwshをインストールすることで利用できるはずです。
Ref: https://ja.developer.box.com/guides/cli/quick-start/powershell-script-templates/#前提条件

完成系

いきなり完成系から記載しちゃいます。以下の例は、Boxのゴミ箱のアイテム全件をマーカーベースのページ割りを使用して取得しCSVに出力するスクリプトになります(ゴミ箱のアイテムってすぐ多くなってウェブアプリで見るのが大変ですよね)。

# 0. Save the current encoding and switch to UTF-8. (Ref: https://stackoverflow.com/questions/58438095/powershell-string-variable-with-utf-8-encoding#answer-58438716)
$prev = [Console]::OutputEncoding
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()

# 1. Get 1st page via marker-based pagination
$raw_data = box request /folders/trash/items --query="""usemarker=true&limit=100""" --fields=body.entries,body.next_marker --json

# 2. Convert JSON string to JSON
$json = $raw_data | ConvertFrom-Json

# 3. Convert JSON to CSV and write it to output.csv
$json.body.entries | Export-Csv -NoTypeInformation -Path .\output.csv -Encoding utf8

$cnt = 0
while( $json.body.next_marker ) {
  # 4. Build the query parameter for the next page
  $next_query = "usemarker=true&limit=100&marker=" + $json.body.next_marker

  # 5. Get 2nd page via marker-based pagination
  $next_data =  box request /folders/trash/items --query="""$next_query""" --fields=body.entries,body.next_marker --json

  # 6. Convert JSON string to JSON
  $json = $next_data | ConvertFrom-Json

  # 7. Append the data for 2nd page to output.csv
  $json.body.entries | Export-Csv -Path .\output.csv -Append -Encoding utf8

  # 8. Repeat step #4 to step #7 until you reach the last page (aka next_marker is null).
  $cnt++
  "Page $cnt, next_marker: " + $json.body.next_marker
}

# Restore the previous encoding.
[Console]::OutputEncoding = $prev

解説

コメントをちょこちょこ入れておりますが、一応各行の処理内容について記載します。

ステップ1

  • BoxCLIにはbox trash(もしくはbox trash:list)というコマンドレットがありますが、前述の通りこちらはページ割りに対応しておらず、1000件以上のアイテムを取得することができません。
  • そこで、box requestという任意のURLやパラメータを指定できるコマンドレットを使用して、マーカーベースのページ割りのパラメータであるusemarker=trueをCLIへと渡します。
  • なお、box requestを使用すると、以下のようにステータスコードやレスポンスヘッダーなど不要な情報も含まれます。
PS C:\Users\kojimaru> box request /folders/trash/items --query="""usemarker=true&limit=100"""
Status Code: 200
Headers:
    Date: 'Sun, 17 Sep 2023 22:47:32 GMT'
    Content-type: application/json
    Transfer-encoding: chunked
    X-envoy-upstream-service-time: '364'
    Box-request-id: 185e9224815c2641f06cad53eeb33f71
    Cache-control: 'no-cache, no-store'
    Strict-transport-security: max-age=31536000
    Via: 1.1 google
    Alt-svc: 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000'
Body:
    Entries:
        -
            Type: folder
            ID: '85557482328'
            Sequence ID: '1'
            ETag: '1'
            Name: '26061'
    Limit: 1
    Next Marker: >-
        eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNORGd5TXpJNGZRIn0

ので、--fields=body.entries,body.next_markerで必要なフィールドのみが出力されるように指定します。また、--jsonでJSON形式になるように指定します

PS C:\Users\kojimaru> box request /folders/trash/items --query="""usemarker=true&limit=100""" --fields=body.entries,body.next_marker --json
{
    "body": {
        "entries": [
            {
                "type": "folder",
                "id": "85557482328",
                "sequence_id": "1",
                "etag": "1",
                "name": "26061"
            }
        ],
        "next_marker": "eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNORGd5TXpJNGZRIn0"
    }
}

※ちなみに

ステップ2

  • ステップ1で取得したデータはJSON形式に成形されてますが、データ型としては文字列なのでConvertFrom-JsonでJSONオブジェクトに変換します。

ステップ3

  • JSONオブジェクトの要素であるbody.entriesの内容(最初のページの100件)をExport-CsvでCSVファイルへと書き出します。
  • -Encoding utf8を指定することでBOM付きのCSVとして出力します(Excelで開く際の文字化け防止)。
  • -NoTypeInformationを指定することでカラムヘッダーの上の行に挿入される不要な行(#TYPE情報ヘッダー)を削除します。

ステップ4

  • body.next_markerが存在する場合(次のページが存在する場合)は、そのmarkerを使用して次のページを取得するためのクエリ文字列を生成します。

ステップ5~8

  • ステップ4のクエリ文字列を使用してリクエストを送信します。
  • 結果をJSONオブジェクトに変換し(ステップ2と同様)、それをCSVファイルに追記(-Append)します
  • body.next_markerが存在する場合(さらに次のページが存在する場合)は、そのmarkerを使用して次のページを取得するため、ステップ4~7を繰り返します。body.next_markerが存在しない場合はこれ以上のアイテムがない(最終ページに到達した)ということなので、ループから抜けて終了します。

ステップ0

  • ここまでの解説ではスルーしてましたが、この前処理は一体なんなのか?これは文字化け防止の処理になります。
  • 今回のスクリプトでは、Box CLI(外部プログラム)で取得した出力結果を変数に代入しているのですが、その際に[Console]::OutputEncodingで定義されたエンコード方式を使用してしまうようです。よって、今回の私の日本語OSのような環境だと、以下のようにshift-jisが使用されることでBox CLIの出力エンコード方式と一致せず、文字化けが起きているようでした。
PS C:\Users\kojimaru> [Console]::OutputEncoding

BodyName          : iso-2022-jp
EncodingName      : 日本語 (シフト JIS)
HeaderName        : iso-2022-jp
WebName           : shift_jis
WindowsCodePage   : 932
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : True
CodePage          : 932

実行

  • スクリプトの内容をコピーして「GetTrashedFolders.ps1」というファイル名に保存して、Powershellから実行してみます。
  • すると以下のようにコンソール上にページ遷移の進捗が記録され、「output.csv:にもりもり各ページのアイテムが追記されていきます。
PS C:\Development\BoxCLI> .\GetTrashedFolders.ps1
Page 1, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOVFE0TXpJNGZRIn0
Page 2, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOVGcxTVRNeWZRIn0
Page 3, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOakU0T1RZM2ZRIn0
Page 4, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOalV4TlRJNGZRIn0
Page 5, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOamcxT1RNeWZRIn0
Page 6, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOekV5TnpJNGZRIn0
Page 7, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOelF3TXpJNGZRIn0
Page 8, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOelkyTnpJNGZRIn0
Page 9, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNOemt5TnpNeWZRIn0
Page 10, next_marker: eyJ0eXBlIjoiT3duZWRCeUZvbGRlciIsImRpciI6Im5leHQiLCJ0YWlsIjoiZXlKMmFXVjNVMk52Y0dVaU9pSmhiR3dpTENKc1lYTjBTV1FpT2pnMU5UVTNPREUzT1RNeWZRIn0
<snip>

おわりに

  • 今回の例ではBox APIで2種類あるページ割りのうち、マーカーベースのページ割りを使用しましたが(こっちのほうがめんどくさそうだったので敢えて)、もう片方のオフセットベースのページ割りbox requestでパラメータとしてoffsetの値を指定しインクリメントしながらページ遷移することで同様のことができると思います。
  • また、ゴミ箱のアイテム取得を例にしましたが、他のリソース(ユーザーやコラボレーションなど)でも同様の処理が可能です。
  • 公式でもCLIを使用したPowershellのスクリプトをいくつか用意しているようなので、そちらも見てみるとおもしろいかも https://ja.developer.box.com/guides/cli/scripts/#powershellスクリプト
]]>
<![CDATA[PostmanでBox APIを使ってみる (JWT認証)]]>https://jikoblog.netlify.app/postman-box-jwt/Ghost__Post__63f6aad483e9300001f54b63Thu, 23 Feb 2023 03:01:40 GMTPostmanでBox APIを使ってみる (JWT認証)

PostmanでJWT認証方式を使用してBox APIを呼べるようにしてみました。

前置き

Box APIでは複数の認証方式があり、公式ではOAuth 2.0を使用したPostmanコレクションが提供されています(手順はこちら)。
https://ja.developer.box.com/guides/tooling/postman/

ここでは、JWT認証を使用してPostmanからBox APIを呼ぶ方法について記載します。

Boxアプリケーションの作成・承認

Box APIを呼ぶにあたり、事前にBoxのカスタムアプリの作成と承認を行います。

  1. まず、Boxの開発者コンソールからJWT認証方式のアプリを作成します。詳しい手順については、公式ページに記載があるのでこちらでは割愛します。
  2. Box管理者としてログインし、#1で作成したアプリの承認を行います。こちらも公式ページに手順があるので割愛します。

なお、#1でアプリを作成する際の「キーペアの生成」手順でダウンロードされる config.json(以下のような形式でJWTアプリの認証に必要となる情報が含まれたファイル)は後述の手順で使用します。

{
  "boxAppSettings": {
    "clientID": "abc...123",
    "clientSecret": "def...234",
    "appAuth": {
      "publicKeyID": "abcd1234",
      "privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\n....\n-----END ENCRYPTED PRIVATE KEY-----\n",
      "passphrase": "ghi...345"
    }
  },
  "enterpriseID": "1234567"
}

Postmanのインストール・設定

  1. Postmanを公式よりダウンロードしインストールします。
  2. こちらのPostman Collectionをインポートします。
    • Postmanで「Import」をクリック ->「Link」のタブでURLを入力し「Continue」をクリック ->「Box API with JWT」を「Import」
      PostmanでBox APIを使ってみる (JWT認証)
    • もしくは、こちらのボタンからコレクションをForkまたImport
  3. Collectionがインポートされたら、そのCollectionのタイトル部分をクリックし、Collection環境変数(当Collection内のみで有効の変数です)を設定します。
    • "config_json" の[CURRENT VALUE]欄に先のBoxアプリ作成の手順でダウンロードされた config.json の内容をそのままコピペします。
      注意: [INITIAL VALUE]欄には絶対貼り付けないでください。こちらにセットされた値はサーバーとの同期の対象になります。
    • 「INIT: Load crypto library for RS512」をクリックし「Send」を実行します。これにより "jsrsasign_js" の環境変数の値が更新されます。
      PostmanでBox APIを使ってみる (JWT認証)

これで準備完了です。

Box APIを呼んでみる

それでは、Box APIを呼んでみましょう。「Get current user」を実行し、以下のようにサービスアカウントの情報(AutomationUser_AppServiceID_RandomString@boxdevedition.com)が返ってきていれば成功です!
PostmanでBox APIを使ってみる (JWT認証)

How it works

ここでは仕組みについて解説します。ざっくり言いますと、PostmanのPre-request Scriptという機能を使用して、リクエストを実行する手前で以下のロジックにて認証処理を行うことでAPIコールが行えるようにしてあります。

基本的には公式の「SDKを使用しないJWT」に記載のNode.jsのコードを踏襲してます。

1. config.jsonの情報を環境変数から取得

const envConfig = pm.collectionVariables.get('config_json')
const config = JSON.parse(envConfig);

2. 外部ライブラリのインポート

JWTアサーションの生成にあたり、JWTクレームに署名をするための暗号化ライブラリを使用したいのですが、残念ながらPre-request ScriptのプラットフォームとなるPostman Sandbox上では標準提供されていないため、requireでインポートすることができません。
回避策(詳細はこちら)として、環境変数として外部のライブラリのコードを丸ごと定義し、その環境変数をロードするという方法を使用します。それが以下の処理です。

// Load the jsrsasign library into Postman Sandbox
const navigator = {};   //fake a navigator object for the lib
const window = {};      //fake a window object for the lib
eval(pm.collectionVariables.get("jsrsasign_js"));   //import javascript jsrsasign

ちなみに、前述の「INIT: Load crypto library for RS512」を実行する手順は、jsrsasignのレポジトリにあるコードをCollection環境変数"jsrsasign_js"へと書き込む処理です。

3. JWTアサーションの生成

jsrsasignにて秘密鍵でJWTクレームを署名し、JWTアサーションを作成します。

// Generate random string for "jti" claim
let newJti = "";
const charset = "abcdefghijklmnopqrstuvwxyz0123456789";

// At Box, it must be at least 16 characters and at most 128 characters
// Ref: https://developer.box.com/guides/authentication/jwt/without-sdk/#3-create-jwt-assertion
for( let i=0; i < 16; i++ ) {
  newJti += charset.charAt(Math.floor(Math.random() * charset.length));
}

// Create Header and Payload objects
const authenticationUrl = "https://api.box.com/oauth2/token";

let header = {
  "kid": config.boxAppSettings.appAuth.publicKeyID,
  "alg": 'RS512'
};

let payload = {
  iss: config.boxAppSettings.clientID,
  sub: config.enterpriseID,
  box_sub_type: "enterprise",
  aud: authenticationUrl,
  jti: newJti,
  exp: Math.floor(Date.now() / 1000) + 45
};

const key = {
  key: config.boxAppSettings.appAuth.privateKey,
  passphrase: config.boxAppSettings.appAuth.passphrase
};

const prvKey = KEYUTIL.getKey(key.key, key.passphrase);

// Prep the objects for a JWT
const sHeader = JSON.stringify(header);
const sPayload = JSON.stringify(payload);

const sJWT = KJUR.jws.JWS.sign(header.alg, sHeader, sPayload, prvKey);

4. アクセストークンをリクエスト

JWTアサーションを送信しアクセストークンと交換します。

pm.sendRequest({
  url: 'https://api.box.com/oauth2/token',
  method: 'POST',
  headers: { 'Content-Type': 'Content-Type: application/x-www-form-urlencoded' },
  body: {
    mode: 'urlencoded',
    urlencoded: [
      { key: 'client_id', value: config.boxAppSettings.clientID, disabled: false },
      { key: 'client_secret', value: config.boxAppSettings.clientSecret, disabled: false },
      { key: 'assertion', value: sJWT, disabled: false },
      { key: 'grant_type', value: 'urn:ietf:params:oauth:grant-type:jwt-bearer', disabled: false }
    ]
  }
}, function (error, response) {
  if (error || response.json().error) {
    // if an error occured, log the error and raise a message to the user.
    console.log(error)
    console.log(response.json())
    throw new Error('Could not get the access token. Check the console for more details.')
  } else {
    // otherwise, fetch the new access token and store it
    const data = response.json()

    // determine when this token is set to expire at
    const newExpiresAt = Date.now() + data.expires_in * 1000
    // store the new variables in the environment
    pm.collectionVariables.set('jwt_access_token', data.access_token)
    pm.collectionVariables.set('jwt_expires_at', newExpiresAt)
  }
})

レスポンスで返ってきたアクセストークンはCollection環境変数"jwt_access_token"へと保存され、実際のリクエストが送信される際に使用されます(またトークンの有効期間内は次回以降のリクエスト実行時にも使用されます)。
PostmanでBox APIを使ってみる (JWT認証)

なお、トークンを失効させたい場合は、「Revoke access token」を実行することで可能です。このリクエストを実行すると、こちらのAPIが送信されトークンが失効された後、リクエスト後の処理(Testsスクリプト)で以下が実行され、Collection環境変数からも削除されます。

pm.collectionVariables.unset("jwt_expires_at");
pm.collectionVariables.unset("jwt_access_token");
]]>
<![CDATA[CLI環境でCharles Proxyを利用して暗号化通信の中身を見る]]>https://jikoblog.netlify.app/decrypt-tls-session-with-charles-proxy-on-cli/Ghost__Post__63a52ccc2bd3e300018606c7Mon, 09 Jan 2023 01:09:09 GMTCLI環境でCharles Proxyを利用して暗号化通信の中身を見る

ここでは、GUIを一切使用せずにCharles Proxyを使用して暗号化通信(HTTPS)のログをキャプチャする方法を紹介します。WindowsやMacなどGUIが使用できる環境ではCharles ProxyのGUIを使用して行えばいいのですが、LinuxサーバーなどGUIが使用できずCLIオンリーの環境で、通信のデバッグを行いたいという需要があったためリサーチしてこの方法にたどり着きました。
※ちなみに別の方法として、環境変数SSLKEYLOGFILEを定義し、pre-master-secretをファイルへと出力しながらtcpdumpを採取するという手段もあると思います。

利用環境

  • OS: Ubuntu 20.04.4 LTS (GNU/Linux 4.4.0-19041-Microsoft x86_64)

本稿では、Debian系のLinuxディストリビューションを使用してます(ちなみに上記バージョン情報の"Microsoft"からわかる通り、WSLのUbuntuです)が、Red hat系のディストリビューションでも(一部コマンドは異なるものの)同様の手順が実施可能な想定です。

Charles Proxyのインストール

Charles Proxyの公式サイトに記載の手順に従ってCharles Proxyのインストールを行います(その記事に、各コマンドの解説も記載されてます)。

$ sudo apt-key adv --keyserver pgp.mit.edu --recv-keys 1AD28806
$ sudo sh -c 'echo deb https://www.charlesproxy.com/packages/apt/ charles-proxy main > /etc/apt/sources.list.d/charles.list'
$ sudo apt-get update
$ sudo apt-get install charles-proxy

インストール後、以下のコマンドを実行しバージョン情報が取得できればOKです。執筆時点ではバージョン4.6.3になりました。

$ charles -version
Charles Proxy 4.6.3

Charles Proxyのルート証明書のインストール

HTTPS通信の中身を確認するにあたり、Charles Proxyのルート証明書をエクスポートし、そのCAを信頼済みにする必要があります。

エクスポートはcharles ssl export <file_name>で行えます。
Ref: https://www.charlesproxy.com/documentation/tools/command-line-tools/

この例ではcharles.crtという名前で証明書をエクスポートします。

$ charles ssl export charles.crt

その後、その証明書を信頼済みCAとして登録します。まず証明書ファイル"charles.crt"をCAストアにコピーします。なんとなく/usr/local/share/ca-certificates/の直下に置くのは憚られたので"mycert"などサブディレクトリを作成して作業しました。

$ sudo mkdir /usr/local/share/ca-certificates/mycert

そこに証明書ファイルをコピーします。

$ sudo cp charles.crt /usr/local/share/ca-certificates/mycert/charles.crt

その後、CAストアをアップデートします。

$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

すると、上記のように証明書が追加されたと標準出力に表示されます。

Charles Proxyの設定

Charles Proxyの設定を行います。が、ここで悲報です。Charles ProxyではCommand-line Toolsの資料を見る限り、設定を行うためのコマンドが用意されてないようです。

ただ、どうやら他のプラットフォームの設定ファイルと互換があるようで、Windows版やMac版のCharles Proxyで使用した設定ファイルをそのままLinux版で使用することができました。なので、他のOS上でCharles ProxyのGUIから必要な設定を行い、その設定ファイルをLinux環境上にコピーして使用します。

各プラットフォームにおける設定ファイルの保存場所は以下の通りです:

  • Windows: %APPDATA%\Charles\charles.config
  • Mac OS X: ~/Library/Preferences/com.xk72.charles.config
  • Linux: ~/.charles.config

Ref: https://www.charlesproxy.com/documentation/faqs/deploying-license-keys-during-installation/

私が使用した設定ファイルをここに記載させていただきます。

設定ファイルをLinux上のホームディレクトリ~/.charles.configに保存する、もしくはCharles Proxy起動時に引数として指定する(以下のコマンド)ことで、その設定ファイルを読み込むことが可能です。

$ charles -config <config_file_name>

重要な設定項目

ここではデフォ値と異なるであろう設定項目についていくつかピックアップします。

SSL proxyingの対象ホスト・ポート

    <sslLocations>
      <locationPatterns>
        <locationMatch>
          <location>
            <host>*</host>
            <port>*</port>
          </location>
          <enabled>true</enabled>
        </locationMatch>
      </locationPatterns>
    </sslLocations>

Web interfaceの有効化

  <remoteControlConfiguration>
    <enabled>true</enabled>
    <allowAnonymous>true</allowAnonymous>
    <users/>
  </remoteControlConfiguration>

Charles Proxyの基本操作

設定ができたらCharles Proxyを起動してみましょう。以下のコマンドでプロセスを起動します。

$ charles

ライセンスを購入してない場合は、以下のように起動後10秒ほど待機時間が発生するので、Readyになるまで待ちます。

$ charles
INFO     com.xk72.charles.CharlesContext                       Loading Configuration
INFO     com.xk72.charles.CharlesContext                       Version 4.6.3
INFO     com.xk72.charles.CharlesContext                       Loading Preferences
Charles is shareware. If you continue using Charles you must pay the shareware fee.
Charles will wait for 10 seconds before starting...
INFO     com.xk72.charles.CharlesContext                       Configuring Access Control List
INFO     com.xk72.charles.CharlesContext                       Starting Proxy Server
INFO     com.xk72.charles.CharlesContext                       Loading Tools
INFO     com.xk72.charles.CharlesContext                       Starting Tools
INFO     com.xk72.charles.CharlesContext                       Configuring Proxies
INFO     com.xk72.charles.CharlesContext                       Ready

Readyなったら起動完了です。

そしたら、もう一つターミナル画面を開きます。Web interfaceを有効化していれば、以下のようにcurlでCharlesのWeb interface(http://contorl.charles/)にCharles Proxy(http://127.0.0.1:8888)をプロキシとしてアクセスすることで、Charles Proxyの様々な操作をすることが可能です。

$ curl -x http://127.0.0.1:8888 http://control.charles/

レスポンスとして、Charles ProxyのメニューがHTMLで返ってきます。

<html>
<head>
    <title>Charles Web Interface</title>
    <link rel="stylesheet" href="css/plain.css" />
</head>
<body>
<h1>Charles Web Interface</h1>
<ul>
    <li><a href="throttling/">Throttling</a></li>
    <li><a href="recording/">Recording</a></li>
    <li><a href="tools/">Tools</a></li>
    <li><a href="session/">Session</a></li>
    <li><a href="quit">Quit</a></li>
</ul>
</body>
</html>

例えば、Recordingメニューを閲覧する場合はrecording/のエンドポイント

curl -x http://127.0.0.1:8888 http://control.charles/recording/

Sessionメニューを閲覧する場合はsession/のエンドポイント

curl -x http://127.0.0.1:8888 http://control.charles/session/

といった感じで操作が行えます。

Charles Proxyでログを採取

それではCharles Proxyで通信ログの採取を行ってみましょう。

まず以下のコマンドででRecordingのメニューを開きます。

$ curl -x http://127.0.0.1:8888 http://control.charles/recording/
<html>
<head>
    <title>Charles Web Interface</title>
    <link rel="stylesheet" href="../css/plain.css" />
</head>
<body>
<h1>Charles Web Interface</h1>
<h2>Recording</h2>
<p>Status: Recording Stopped</p>
<ul>
    <li><a href="start">Start</a></li>
    <li><a href="stop">Stop</a></li>
    <li><a href="../">Back</a></li>
</ul>
</body>
</html>

上記より、Recordingの開始はstartのエンドポイント、停止はstopのエンドポイントと分かります。

start/のエンドポイントにアクセスし、Recordingを開始します。

$ curl -x http://127.0.0.1:8888 http://control.charles/recording/start
<html>
<head>
    <title>Charles Web Interface</title>
    <link rel="stylesheet" href="../css/plain.css" />
</head>
<body>
<h1>Charles Web Interface</h1>
<h2>Recording</h2>
<p>Status: Recording</p>
<ul>
    <li><a href="start">Start</a></li>
    <li><a href="stop">Stop</a></li>
    <li><a href="../">Back</a></li>
</ul>
</body>
</html>

上記のように"Status: Recording"というレスポンスが返っていれば、Recordingが開始されている状態です。

その状態で、キャプチャしたい通信を行います。ここでは例としてcurlを使用した通信を行います。
まずcurlの通信がCharles Proxyを経由するように環境変数を定義してCharles Proxyをプロキシとして指定します。

export http_proxy='http://127.0.0.1:8888'
export https_proxy='http://127.0.0.1:8888'

その後、通信を行います。

$ curl --location --request GET 'https://api.box.com/2.0/users/me' --header 'Authorization: Bearer 68l2JTE0wOQRM7tsC83ZDV8xl8GM11B0'

キャプチャしたい通信が完了したら、Charles ProxyでRecordingした内容をログファイルへと書き出します。

session/のエンドポイントにアクセスすることで、出力可能なフォーマットとそのコマンドを閲覧できます

$ curl -x http://127.0.0.1:8888 http://control.charles/session/
<html>
<head>
    <title>Charles Web Interface</title>
    <link rel="stylesheet" href="../css/plain.css" />
</head>
<body>
<h1>Charles Web Interface</h1>
<h2>Session</h2>
<ul>
    <li><a href="clear">Clear Session</a></li>
    <li><a href="export-xml">Export Session as XML</a></li>
    <li><a href="export-json">Export Session as JSON</a></li>
    <li><a href="export-trace">Export Session as Trace</a></li>
    <li><a href="export-csv">Export Session as CSV</a></li>
    <li><a href="export-har">Export Session as HAR</a></li>
    <li><a href="download">Download Session</a></li>
    <li><a href="../">Back</a></li>
</ul>
</body>
</html>

例えば、JSONで保存する場合はexport-jsonのエンドポイント

$ curl -x http://127.0.0.1:8888 http://control.charles/session/export-json --output <output_file_name>

Traceで保存する場合は/export-traceのエンドポイント

$ curl -x http://127.0.0.1:8888 http://control.charles/session/export-trace --output <output_file_name>

といった感じです。

TraceファイルをCharles Proxyで開くことで、復号された通信の内容を確認することができます。

CLI環境でCharles Proxyを利用して暗号化通信の中身を見る

Common Errors

Web interfaceが有効化されてない

  • Error:
<html>
<head>
    <title>Charles Web Interface</title>
</head>
<body>
<h1>Charles Web Interface</h1>
<p>The Web Interface is disabled. You can enable it in the Web Interface Settings in the Proxy menu.</p>
</body>
  • Cause: Web interfaceの有効化がされてない状態で、http://control.charlesに接続が行われた。
  • Solution: この手順を実施して、設定ファイルよりWeb Interfaceを有効化する。

Charles Proxyとの接続ができない

  • Error:
curl: (7) Failed to connect to 127.0.0.1 port 8888: Connection refused
  • Cause: Charles Proxyが起動してない、もしくは起動しているポート番号が8888とは異なっている。
  • Solution: Charles Proxyが起動しているか確認、また接続先のポート番号と設定ファイルで指定されているポート番号(以下の箇所)が一致しているか確認する。
  <proxyConfiguration>
    <-- 略 -->
      <port>8888</port>
    <-- 略 -->
  </proxyConfiguration>

SSLエラー

  • Error:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8888
  • Cause: Charles ProxyのSSL証明書が信頼されていない。
  • Solution: この手順の証明書がインストールされていることを確認する。また、証明書インストール後、再起動が必要かも(自身がこのエラーにヒットした時は、OSの再起動で解消された記憶)。
]]>
<![CDATA[Ghost で任意の image url を Featured Image に指定する]]>https://jikoblog.netlify.app/ghost-choose-external-url-for-featured-images/Ghost__Post__62ca526f68d2c60001afd03eSun, 10 Jul 2022 04:52:06 GMTGhost で任意の image url を Featured Image に指定する

Ghost で記事を作成する際、アイキャッチ画像(Featured Image)に外部ソースの画像を指定する方法について紹介します。

前置き

ブログで記事を作成する際、画像や動画などのメディアは別のサーバー(AWS S3やGoogle Cloud Storageなど)で管理したい、ということはないでしょうか。

Ghostでは記事内の画像は外部URLを指定できるものの、残念ながらアイキャッチ画像(Featured Image)に関してはGhostサーバーにアップロードしたファイルしか指定できないようです。以下はForumの関連記事です。

Allow external URLs for feature images
Would it be possible to have an option to enter the url for an already existing image as an alternative to uploading it? I see that the Unsplash option does just this, so I guess the heavy-lifting setup is already in place.
Ghost で任意の image url を Featured Image に指定する

やり方

上記記事の通り、Ghostのユーザーインターフェースからは外部URLは指定できないようなのですが、Ghostのデータベースを直接書き換えるという力業を使えば、無理くり外部URLを参照できるようになります。

Ghostのデータベースpostsというテーブルがあり、そこに記事のレコードが登録されております。そのテーブルにはfeature_imageという列があるので、対象のレコードのこのフィールドを任意の値で書き換えることで、実現ができます。

Ghost で任意の image url を Featured Image に指定する

こちらの記事のようにローカル環境で動かしている場合は、ローカルの作業ディレクトリ配下にghost.dbというDBファイルがあるので、これをDB Browserなどで開き編集することで、簡単に書き換えることができます。

]]>
<![CDATA[Ghost + Gatsby + Netlify でブログを開設]]>https://jikoblog.netlify.app/ghost-gatsby-netlify/Ghost__Post__62c60ff40b910a00012ac483Sun, 10 Jul 2022 02:23:11 GMTGhost + Gatsby + Netlify でブログを開設

Ghost + Gatsby + Netlify でブログを開設しましたので、手順についてメモします。以前は、WordPressを使ってブログを運用していたのですがメンテナンスに限界を感じ、別のCMSを探したところ、この構成にたどり着きました。この構成を使用することで、シンプルかつ高速なブログを作成することができました。

Tech stack

ざっくりですが、使用した技術スタックについてひとことずつ

  • Ghost: コンテンツマネジメントシステム(CMS)。Ghostでブログを書きます。
  • Gatsby: 静的サイトジェネレータ(Static Site Generator)。Ghostで作成したブログ記事を静的コンテンツへと変換します。
  • Netlify: ホスティングサービス。Gatsbyで生成した静的コンテンツをここにホスティングし、Webで閲覧できるようにします。

利用環境

以下を使用しました

  • Docker version: 20.10.14, build a224086
  • Node version: v16.15.0
  • Gatsby CLI: 4.15.0
  • Netlify CLI: netlify-cli/10.3.3 win32-x64 node-v16.15.0

Ghost

CMSしてGhostを使用します。Ghostのホスティングサービスを利用すると有償になるのですが、オープンソースプロジェクトとしてソースコードを公開してくれているので、そちらを利用してローカル上でGhostサーバーを立てることができます。簡単にやる方法しては、以下の2通りになると思います。

Dockerを使用する

Ghost公式のDocker Imageがあるので、それを利用します。作業ディレクトリに、docker-compose.ymlを作成し、以下を記述します。

version: '3'
services:
  ghost:
    image: ghost
    restart: always
    volumes:
      - ./ghost:/var/lib/ghost/content
    ports:
      - 2368:2368

その後、以下のコマンドを実行すると、Ghostサーバーを http://localhost:2368/ で開始できます。

$ docker-compose up

なお、作業ディレクトリ直下に「ghost」というフォルダが作成され、そこに作成したコンテンツが保存されます。

Ghost CLIを使用する

Dockerを使用しなくても、Ghost CLIを利用することで、Ghostサーバーを立てることができます。CLIのインストールは以下のコマンドで行います。

$ npm install ghost-cli@latest -g

その後、作業ディレクトリで以下のコマンドを実行し、サーバーの起動に必要なモジュールのインストールを行います。

$ ghost install local

作業ディレクトリ配下のパス「ghost/content」に作成したコンテンツが保存されます。

上記実施後、ブラウザで http://localhost:2368/ にアクセスすると、ローカルで起動しているGhostサーバーに接続できます。
http://localhost:2368/ghost にアクセスすると管理者ページに入ることができます。初回はユーザ未作成状態なので、「Create account」をクリックして管理者ユーザーを作成します。

Ghost + Gatsby + Netlify でブログを開設

その後、ダッシュボードから、[Settings] (ギアアイコン) > [Integrations] > [Add custom integration] と遷移し、任意の名前で新たなカスタム連携を作成します(このカスタム連携のAPI Keyは後の手順で使用します)。

Ghost + Gatsby + Netlify でブログを開設

ここまででGhostの準備は完了です。

Gatsby

次にGatsbyを使用して、Ghostサーバーのブログ記事を静的コンテンツ(Static HTML)へと変換する作業を行います。Ghostが公式のスターターテンプレートを出しているのでそちらを利用します。もしくは、サードパーティーがテーマのプラグインを公開してくれているので、そちらも利用可能です。Gatsbyサイト内で"ghost"でプラグインを検索して探すことができます(例: https://github.com/styxlab/gatsby-theme-try-ghost )。

お好きなテンプレートをローカルへとクローンしてDependenciesのインストールを行います。

$ git clone https://github.com/TryGhost/gatsby-starter-ghost.git
$ cd gatsby-starter-ghost
$ yarn

Gatsby-CLIを利用する場合は以下のコマンドになります

$ gatsby new gatsby-starter-ghost https://github.com/TryGhost/gatsby-starter-ghost.git

その後、レポジトリ直下(「gatsby-starter-ghost」直下)の.ghost.jsonファイルに先の手順で作成したGhostのカスタム連携のAPIキーを入力します。

{
   "development": {
     "apiUrl": "http://localhost:2368",
     "contentApiKey": "f64alfad618e7f896358ab0273"
   },
   "production": {
     "apiUrl": "http://localhost:2368",
     "contentApiKey": "f64alfad618e7f896358ab0273"
   }
}

ここまでできたら、gatsby build(もしくはyarn build)を実行すると http://localhost:2368/ のGhostサイトの静的コンテンツが生成できます。生成された静的コンテンツは、レポジトリ直下(「gatsby-starter-ghost」直下)のpublicフォルダに格納されます。

ちなみに、gatsby serve(もしくはyarn serve)を実行すると、http://localhost:9000/ でGatsbyによってビルドされた静的コンテンツがどのように表示されるか確認することができます。

Netlify

作成された静的コンテンツをNetlifyへとデプロイします。Netlifyアカウントを未作成の場合は、アカウントを作成し(無償でできます)、アプリを作成しておきます。

レポジトリ直下に遷移した状態で、以下のコマンドを実行しNetlifyにログインします。

$ netlify login

その後、以下のコマンドでNetlifyにデプロイを行います。

$ netlify deploy -p

上記コマンド実施時に、デプロイ先のアプリ名などが聞かれるので、それらに回答すると静的コンテンツがNetlifyへとアップロードされ、Web上でページが閲覧できるようになります。

おさらい

ブログ作成の流れをおさらいしていきます。

ブログを更新する際は

  1. Ghostサーバーを起動し、ローカル上で編集を行います
  2. 編集後、Gatsbyで静的コンテンツへと変換します
  3. 静的コンテンツをNetlifyへとデプロイします

フォルダ構成

- gatsby-starter-ghost/
    |- src
    |- static
    |- .ghost.json <- これを編集する
    |- netlify.toml <- Netlifyのビルド設定
    |- public <- ここにGatsbyでビルドした静的コンテンツが生成される
    |- package.json
    |- etc.
- ghost/ <- Ghostサーバー(Docker)で作成したコンテンツがここに格納される(このフォルダはバックアップをすべき)
    |- apps
    |- data
    |- files
    |- images
    |- logs
    |- media
    |- public
    |- settings
    |- themes    
- docker-compose.yml
]]>
<![CDATA[PostmanでZaim APIを使ってみる]]>https://jikoblog.netlify.app/zaim-api-with-postman/Ghost__Post__62991dd7e25194000155e3efSun, 15 May 2022 15:21:47 GMTPostmanでZaim APIを使ってみる

Postmanを使用してZaim APIを試してみました。Zaim APIは認証方式としてOAuth 1.0を利用しているようなのですが、その認証方式の前提知識なしでPostmanにてサクッと試したい方の参考になればと思います。

Zaim APIを利用するまでの流れ

以下の流れでZaim APIの利用が開始できます。

  1. Zaimアプリを作成する
  2. Zaimアプリを使用してアクセストークンを取得する
    1. リクエストトークンを取得
    2. ユーザーとしてログインしアプリを認可する
    3. アクセストークンを取得
  3. アクセストークンを使用してZaim APIを使用する

※事前にZaimのアカウントの作成とPostmanのインストールは完了している前提です。

1. Zaimアプリの作成

Zaim APIの使用にあたり、まずアプリの作成が必要になりますので、以下の手順で作成を行います。

  1. Zaim Developer Center(https://dev.zaim.net/home)にログインします。
  2. [新しいアプリケーションを追加] を押下するとアプリの情報を入力する画面になるので、埋めていきます(基本的にいずれの項目も任意の値で大丈夫ですが、[アクセスレベル]については必要な権限のみを有効化しておくことがいいと思います)。
PostmanでZaim APIを使ってみる
  1. アプリの登録が完了したら、追加されたアプリの情報を確認します。
PostmanでZaim APIを使ってみる

以下の情報はこの後の手順で使用するので控えておきます。

  • コンシューマ ID: 6f5ae0b1f7ce0944f9b28109607b949aa4ab7e97
  • コンシューマシークレット: 4d37fda7bcb84d8949910ca06ee3cb0e09659641

コンシューマIDやコンシューマシークレット、またこの後に登場するトークンなどの情報は秘匿情報です。本記事ではマスキングせずに記載しております(執筆後、無効化して利用できなくしております)が、自身のものは外部に漏らさないようお気をつけください。

2. アクセストークンを取得する

手順1で作成したZaimアプリを使用してアクセストークンを取得します。

2-1. リクエストトークンを取得

まず、リクエストトークン取得URL(https://api.zaim.net/v2/auth/request)を使用してリクエストトークンを取得します。Postmanで新規タブを開き、以下を入力してリクエストを送信します。

  1. Request URL: https://api.zaim.net/v2/auth/request (リクエストトークン取得URL)
  2. Method: GET
  3. Authorizationタブで以下を設定
    1. Type: OAuth 1.0
    2. Signature Method: HMAC-SHA1
    3. Consumer Key: 6f5ae0b1f7ce0944f9b28109607b949aa4ab7e97 (コンシューマIDの文字列)
    4. Consumer Secret: 4d37fda7bcb84d8949910ca06ee3cb0e09659641 (コンシューマシークレットの文字列)
    5. Callback URL: http://localhost (空欄にはできないので、任意のURLを入力)
PostmanでZaim APIを使ってみる

リクエストを送信すると、レスポンスで以下が返ってきます。

oauth_token=5ra2lInLI8MkJwqD9HGY2KKrVOMLyDe3qLYgesyMLrkmr2HeVAkujRl7OyyoRAaTbiyHkSEhPw&oauth_token_secret=xUfruOQ2h9zObc1sUKoPuPZOySP968YA9gGW7sVaJohqBxJ3BRq7y7eRxcInCzY8Fqsg&oauth_callback_confirmed=true

これらの値は後続の手順で使うので控えておきます。

  • oauth_token: 5ra2lInLI8MkJwqD9HGY2KKrVOMLyDe3qLYgesyMLrkmr2HeVAkujRl7OyyoRAaTbiyHkSEhPw
  • oauth_token_secret: xUfruOQ2h9zObc1sUKoPuPZOySP968YA9gGW7sVaJohqBxJ3BRq7y7eRxcInCzY8Fqsg

2-2. ユーザーとしてログインしアプリを認可する

次に、認証URL(https://auth.zaim.net/users/auth)を使用して、アプリの認可を行います。ブラウザを起動し、アドレスバーに以下のURLを入力します(oauth_tokenの値は、手順2-1で取得したものを使用)。

https://auth.zaim.net/users/auth?oauth_token=J6CpTLv0Ye9Axq3AwHFtM7A59TuTx61HuywUaOwjLm5N2BLBDTTHdeDprgn066ZSiQLog

すると認証を求められるので、お使いのZaimユーザーとしてログインします。

PostmanでZaim APIを使ってみる

ログイン後、このようなページになります。

PostmanでZaim APIを使ってみる

本来ならCallback URLに設定されたURL(私の場合はhttp://localhost)にリダイレクトされるはずなのに、なぜかされない(Zaimの不具合?)ので一見失敗したように見えますが、開発者ツールを開くと、Verifierの情報が見えるので、その情報を控えておきます。

PostmanでZaim APIを使ってみる
<div class="callback">http://localhost?oauth_token=5ra2lInLI8MkJwqD9HGY2KKrVOMLyDe3qLYgesyMLrkmr2HeVAkujRl7OyyoRAaTbiyHkSEhPw&oauth_verifier=MNIet9Pqi6qrwrklpsxB8zROwr1L9aQe7Qr58KEevDs1FeYfiuMLOkvXumSlHjuPtFuNiPkjA<div class="callback_end"></div></div>

2-3. アクセストークンを取得

最後にアクセストークン取得URLを使用して、アクセストークンを取得します。Postmanでまた新たにタブを開き、以下の情報を入力してリクエストを送信します。

  1. Request URL: https://api.zaim.net/v2/auth/access (アクセストークン取得URL)
  2. Method: POST
  3. Authorizationタブで以下を設定
    1. Type: OAuth 1.0
    2. Signature Method: HMAC-SHA1
    3. Consumer Key: 6f5ae0b1f7ce0944f9b28109607b949aa4ab7e97 (コンシューマIDの文字列)
    4. Consumer Secret: 4d37fda7bcb84d8949910ca06ee3cb0e09659641 (コンシューマシークレットの文字列)
    5. Access Token: 5ra2lInLI8MkJwqD9HGY2KKrVOMLyDe3qLYgesyMLrkmr2HeVAkujRl7OyyoRAaTbiyHkSEhPw
    6. Token Secret: xUfruOQ2h9zObc1sUKoPuPZOySP968YA9gGW7sVaJohqBxJ3BRq7y7eRxcInCzY8Fqsg
    7. Callback URL: 空欄
    8. Verifier: MNIet9Pqi6qrwrklpsxB8zROwr1L9aQe7Qr58KEevDs1FeYfiuMLOkvXumSlHjuPtFuNiPkjA (手順2-2で取得したもの)
PostmanでZaim APIを使ってみる

リクエストを送信すると、レスポンスで以下が返ってきます。

oauth_token=b2nhZHrMHjgBVA5zm2uAKZzOX5yUcIRsjDBsvaYZ1ALX60Wp97Q5LDt7zL7xCvnYTMVjhew&oauth_token_secret=xUfruOQ2h9zObc1sUKoPuPZOySP968YA9gGW7sVaJohqBxJ3BRq7y7eRxcInCzY8Fqsg

この手順で返ってきたoauth_tokenとoauth_token_secretで、ZaimのAPIを使用することができます。

  • oauth_token: b2nhZHrMHjgBVA5zm2uAKZzOX5yUcIRsjDBsvaYZ1ALX60Wp97Q5LDt7zL7xCvnYTMVjhew
  • oauth_token_secret: xUfruOQ2h9zObc1sUKoPuPZOySP968YA9gGW7sVaJohqBxJ3BRq7y7eRxcInCzY8Fqsg

3. Zaim APIを使用してみる

Postmanでまた新たにタブを開き、以下の情報を入力します。

  1. Request URL: https://api.zaim.net/v2/home/user/verify (ユーザー情報取得エンドポイント
  2. Method: GET
  3. Authorizationタブで以下を設定
    1. Type: OAuth 1.0
    2. Signature Method: HMAC-SHA1
    3. Consumer Key: 6f5ae0b1f7ce0944f9b28109607b949aa4ab7e97 (コンシューマIDの文字列)
    4. Consumer Secret: 4d37fda7bcb84d8949910ca06ee3cb0e09659641 (コンシューマシークレットの文字列)
    5. Access Token: b2nhZHrMHjgBVA5zm2uAKZzOX5yUcIRsjDBsvaYZ1ALX60Wp97Q5LDt7zL7xCvnYTMVjhew (手順2-3で取得したもの)
    6. Token Secret: xUfruOQ2h9zObc1sUKoPuPZOySP968YA9gGW7sVaJohqBxJ3BRq7y7eRxcInCzY8Fqsg
    7. Callback URL: 空欄
    8. Verifier: 空欄
PostmanでZaim APIを使ってみる

レスポンスとしてユーザー情報が返ってきます。

{
    "me": {
        "login": "72904a1866b2",
        "input_count": 2,
        "day_count": 2,
        "repeat_count": 1,
        "id": 8626511,
        "currency_code": "JPY",
        "week": 0,
        "month": 1,
        "active": 1,
        "day": 1,
        "profile_modified": "2021-11-29 07:16:06",
        "name": "kojimaru",
        "created": "2021-11-29 07:15:40",
        "profile_image_url": "https://s3-ap-northeast-1.amazonaws.com/zaim.net/public/images/users/_default/90x90.png",
        "cover_image_url": "https://s3-ap-northeast-1.amazonaws.com/zaim.net/public/images/covers/_default/90x90.png"
    },
    "requested": 1652588562
}

ほかのAPIエンドポイントも、同じ認証情報を使用して利用可能です。以下がデベロッパー向けのドキュメントへのリンクです(ログイン必須)。

Ref: https://dev.zaim.net/home/api

トークンの無効化

Zaim APIにはトークンを無効化するエンドポイントは用意されてない(ドキュメントには見当たらず)ようなので、UIからやる必要があるようです。私が見つけた手順は以下の通りです。

  1. Zaimにhttps://zaim.net/よりログインする
  2. ログイン後、右上の[設定]より[ソーシャルログイン]を選択する
  3. [Zaim で認証]以下に認証済みアプリの一覧が出てくるので、その中で対象のアプリを見つけ[無効にする]を押下する
PostmanでZaim APIを使ってみる
  1. その後は、上記手順で払い出したトークンが利用できなくなり、APIを利用すると認証エラー(401 Unauthorized)になる
PostmanでZaim APIを使ってみる

]]><![CDATA[Wordpressのサーバー移行時に、旧サーバーで管理画面だけ入れるようにする方法]]>https://jikoblog.netlify.app/wordpress-configuring-redirection-during-migration/Ghost__Post__62991dd7e25194000155e3eeSun, 15 May 2022 08:04:36 GMTWordpressのサーバー移行時に、旧サーバーで管理画面だけ入れるようにする方法

WordPressのお引越し(ドメイン変更を含む)をした後、旧サーバーの管理画面にどうしても入る必要ができてしまいました。が、旧ドメインから新ドメインへのリダイレクトが設定済みだったので、旧サーバーにアクセスしても新サーバーにリダイレクトされて旧サーバーの管理画面に入れない状態に。。。回避方法を見つけたのでメモしておきます。

やりたいこと

  • ページの訪問者が、旧サーバーのページにアクセスした際は、新サーバーにリダイレクトする。
  • WordPressの管理者だけは、旧サーバーの管理画面にアクセスした際、新サーバーにリダイレクトせず管理画面を使用できるようにする。

対処方法

自身の検証より、Wordpressの管理画面に接続する際は、基本的に以下のパスが使用されることに気づきました。

https://old_domain.com/wp/xxx
https://old_domain.com/app/xxx

/wp/もしくは/app/で始まるパスが使用されるようなので、これらのパスにアクセスがあった場合はリダイレクトしないように設定を書き換えることで実現できました。

設定内容

リダイレクトの設定は様々な方法でできると思いますが、私の場合はnginx.confの設定でこれを行いました。

私の場合、移行元のサーバーではHeroku上でNginxをWebサーバーとして使用していたので、nginx.confこの辺)に以下を追記しました(Apacheをご利用の方は、.htaccessの変更が必要になると思います)

location ~* ^/(?!(wp|app)/) {
    rewrite ^ https://new_domain.com$request_uri? permanent;
}

上記は、/wp/もしくは/app/始まらないパスである場合のみ、新サーバーにリダイレクトを行うという設定になります(正規表現チェッカーで確認できます)。

参考記事: https://stackoverflow.com/questions/16302897/nginx-location-not-equal-to-regex#answer-39549548

設定後は、以下のURLに直接行くと、新サーバーにリダイレクトされずに旧ドメインで管理画面に入れるようになりました。

https://old_domain.com/wp/wp-admin/
]]>
<![CDATA[Wordpressアップデート後、管理画面に入れない]]>https://jikoblog.netlify.app/wordpress-unable-to-login/Ghost__Post__62991dd7e25194000155e3edSat, 14 May 2022 22:25:18 GMTWordpressアップデート後、管理画面に入れない

WordPressのバージョンをアップデートした後、管理画面に入ろうとすると/wp/wp-admin/upgrade.php?_wp_http_referer=%2Fwp%2Fwp-admin%2Fへとリダイレクトされ続け、「更新の必要はありません WordPress のデータベースはすでに最新です !」と表示されて、入れなくなってしまいました。解決方法について記載します。

発生原因

この画面にリダイレクトされる原因は、Wordpressのバージョンアップ後、Wordpressのバージョン情報がウェブサーバー側とデータベース側とで一致しないことで起きるようです。

Ref: https://github.com/WordPress/WordPress/blob/master/wp-admin/admin.php#L51-L55

対処方法

ということで、Wordpressのバージョンをデータベース側のバージョンと比較してみました。

WordPressのバージョンはwp-includes/version.phpwp_db_versionにセットされています。

$ heroku run bash -a jikoblog
Running bash on ⬢ jikoblog... up, run.4394 (Free)
~ $ pwd
/app
~ $ grep "wp_db_version =" web/wp/wp-includes/version.php
$wp_db_version = 51917;

データベース側では、wp_optionsテーブルのdb_versionというカラムにセットされています。

Wordpressアップデート後、管理画面に入れない

ここで両者のバージョンがなぜか一致してない場合は、Wordpressのバージョン($wp_db_version)をデータベースに格納されているバージョン(wp_optionsdb_version)と合わせてあげることで、とりあえず例の画面は突破し管理画面に入れるようになると思います。

ちなみに、私の場合は↑の通りバージョンが両方とも51917で一致してました。にも関わらず、本現象が起きており数時間ほど迷ってしまったのですが、結果的に犯人はRedisサーバーでした。アップデート作業時にRedisの情報が更新されてなかったようで、、、heroku redis:cliでHerokuのRedisに接続し、flushallコマンドでRedisのデータをクリーンアップしたら、その後はMySQLデータベースの最新の情報が取得され、現象が解消し管理者ページには入れるようになりました。

$ heroku redis:cli
Connecting to redis-asymmetrical-69722 (HEROKU_REDIS_MAUVE_TLS_URL, HEROKU_REDIS_MAUVE_URL, REDIS_TLS_URL, REDIS_URL):
ec2-44-196-208-213.compute-1.amazonaws.com:22940> flushall
OK

ほかにもパフォーマンス向上のためのキャッシュ関連のプラグインを利用していると、私のようにデータベースは更新されているのに、キャッシュの情報が参照されていることで同様の現象になることが起こりうると思います。ご注意を!

]]>
<![CDATA[WMware Workspace ONE + Android Enterprise + Box を設定してみた]]> [Workspace ONE] > [Android EMM 登録] の順に進み、[構成]を選択します。 ※私はすでに登録済みなので[構成]ではなく[編集]ボタンになっております。 2. 「Android EMM 登録」 ページにリダイレクトされるので、[Google に登録する] を選択しま]]>https://jikoblog.netlify.app/wmware-workspace-one-android-enterprise-box/Ghost__Post__62991dd7e25194000155e3ecThu, 29 Apr 2021 08:27:29 GMTWMware Workspace ONE + Android Enterprise + Box を設定してみた

WMware Workspace ONEをMDMとしてAndroid Enterpriseを利用し、Box for EMMを設定してみました。手順をメモっときます。
Intuneの時と同様、公式の資料がないところは割と手探りでやりました。間違い等ございましたら、ご指摘いただけますと幸いです。

VMware Workspace ONE 側の設定 (Android Enterprise編)

こちらの公式の資料の手順に従って、Workspace ONE側でAndroid Enterpriseの設定を行います。ここでは本手順の内容をかいつまんで記載します。うちはGSuiteユーザーではないので、GSuiteユーザーでない方の手順を使用してます。

  1. [はじめに] > [Workspace ONE] > [Android EMM 登録] の順に進み、[構成]を選択します。
    ※私はすでに登録済みなので[構成]ではなく[編集]ボタンになっております。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. 「Android EMM 登録」 ページにリダイレクトされるので、[Google に登録する] を選択します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. Googleアカウントでサインインし、開始 を選択します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 Google
  1. 組織名 などの項目を入力し、[確認] > [登録を完了] の順に選択すると、Workspace ONE コンソールにリダイレクトされます。Google サービス アカウント認証情報が自動的に入力されているので、[保存] を選択します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc

VMware Workspace ONE 側の設定 (Box編)

こちらの公式の資料の手順を参考に、Box for Androidを管理対象アプリケーションとしてデバイスにプッシュするための設定を行います。

  1. いきなり資料の手順とそれますが、まず事前準備として[Public ID]の発行をBoxサポートに依頼します。[Public ID]は後述の手順で使うのですが、発行のリードタイムが発生するので、事前に依頼しておきましょう。必要情報はこちらを参照。
  2. Workspace ONE UEM コンソールで、[アプリケーションとブック] > [アプリケーション] > [リスト ビュー] > [公開] の順に移動して、[アプリケーションを追加] を選択します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. [プラットフォーム] でAndroidを選択し、[名前] テキスト ボックスに、アプリケーション ストアで Box for Android を検索するためのキーワードとして「Box」を入力します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. [次へ] を選択し、検索結果の中から「Box」を選択します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. デバイスでBoxアプリに必要な権限を確認し、[承認] を選択します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. [詳細]、[利用規約]、[SDK] を必要に応じて設定し、[保存して割り当て] を選択してアプリを保存します。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. 保存後、[割り当て] タブに遷移するので、「割り当てを追加」 を選択し、こちらの公式資料を参考に必要な詳細を構成します(例: 必要なユーザーグループを割り当てる、など)。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  1. [アプリケーション構成]の部分は、以下の設定が必要になります。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
© 2021 VMware, Inc
  • User email: {EmailAddress}
  • Public Id: [手順#0でBoxサポートから提供された文字列を入力]
  • Management Id: {ManagementID}
  • EMM Name: Airwatch
  • Billing Id: [任意の文字列]
  • Intune Enterprise: 0
  • Microsoft User Principal Name: [任意の文字列]

上記設定後、保存を押したらWorkspace ONE UEMコンソールでの作業は完了です!

モバイル端末(Android)側の設定

モバイル端末をWorkspace ONEの管理下とし、その後Box for Androidをインストールします。

  1. Google Playストアより「Intelligent Hub」アプリをインストールします。
Ref: https://play.google.com/store/apps/details?id=com.airwatch.androidagent&hl=ja&gl=US
  1. 「Intelligent Hub」アプリを開き、お使いのWorkspace ONE環境の情報を入力しユーザー認証を行います。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
  1. ユーザー認証後、利用規約など同意を求められるので、諸々同意して進みます。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
  1. 一通り進めると、仕事用プロファイルのセットアップが開始されます。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
  1. セットアップが完了すると、仕事用プロファイルのアプリ(カバンのマークが入ったもの)が追加されます。
WMware Workspace ONE + Android Enterprise + Box を設定してみた
  1. 仕事用プロファイルの「Play Store」を開くと、「Box」アプリが表示されます。
WMware Workspace ONE + Android Enterprise + Box を設定してみた

こちらをインストールすると仕事用プロファイルの(Workspace ONE管理下の)Boxアプリが端末にプロビジョンされます。

事後確認

仕事用プロファイルのBoxアプリを開き、ログインが行えるか確認を行います。

自社Boxインスタンス内のユーザーであれば、ログインが可能です。ちなみに、Boxのユーザーアクティビティレポートでは、「Box for Android EMM Phone」からのログインとして記録されるようです。

WMware Workspace ONE + Android Enterprise + Box を設定してみた

しかし、自社Boxインスタンス外のユーザーであれば、ログインが失敗します。

WMware Workspace ONE + Android Enterprise + Box を設定してみた
]]>
<![CDATA[HiveQLでMIMEエンコードされたデータをデコードする]]>https://jikoblog.netlify.app/hiveql-decoding-mime-encoded-data/Ghost__Post__62991dd7e25194000155e3ebSat, 17 Apr 2021 17:30:10 GMTHiveQLでMIMEエンコードされたデータをデコードする

アプリケーションログの保存先として使用しているHiveにMIMEエンコードされた状態で保存されていたデータがあったので、HiveQLでデコードする方法を考えてみました。HiveQLの関数だけでやろうとするとあまりいい方法が思いつきませんでしたが、とりあえず実現する方法は編み出したのでメモっときます。

はじめに - HiveQLとは

HiveQLとは一言でいうとHive上で使用できるSQLに似たクエリ言語になります。Hiveって何?って方は、こちらのページの説明がわかりやすいと思ったので、リンクさせていただきます。

要点をまとめると、Hive (Apache Hive) とはSQL(厳密にはHiveQLというSQLに近い言語)を使用してHDFS (Hadoop Distributed File System)のデータを集計・分析することを可能にするソフトウェアです。HDFSは複数のコンピューターのハードディスクを一つのストレージのように扱えるスケーラブルな分散型ファイルシステムであり、大規模なデータを格納できますが、データ集計を行う際MapReduceジョブ(各コンピューターに分割された大量のデータを分散処理するためのフレームワーク)を自身で定義(プログラミング)しなければなりません。そこで開発されたのがHiveで、MapReduceの知識がなくてもHiveQLというSQLライクな言語でHadoop上のデータを解析できます!

HiveQLはSQLをベースにしているものの、フルサポートしているわけではないため、一部使用できない構文もあるようです。以下のページにHiveQLの言語レファレンスがございます。

Ref: https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF

MIMEエンコードについて

MIMEとは、規格上ASCII(7bit文字)のテキストしか使用できないインターネットの電子メールでさまざまなフォーマット(書式)を扱えるようにする規格です。日本語などnon-ASCIIの文字も、MIMEエンコードしASCII文字に変換することでメールで使えるようになります。

メールヘッダー上にASCII以外の文字列を含める場合は、以下のような形式で指定します。

=?文字セット?エンコード方式?エンコードされた文字列?=

文字セット(charset)はUTF-8、エンコード方式(Content-Transfer-Encoding)はBase64でエンコードされたSubjectヘッダー(件名)は例えば以下のような文字列になります。

Subject: =?UTF-8?B?55m76Yyy44GX44Gf44Oh44O844Or44Ki44OJ44Os44K544KS56K66KqN44GX?= =?UTF-8?B?44Gm44GP44Gg44GV44GE?=

今回の例ではこの組み合わせ(=?UTF-8?B?)でエンコードされた文字列をHiveQLを使用してデコードしていきます。

メールデコード処理の流れ

全体の流れとしては以下のようになります:

  1. 元の文字列を「=?UTF-8?B」で区切って分割(splitを使用)し、エンコードされた文字列部分を配列に格納する
  2. 配列の各要素のエンコードされた文字列をBinaryに変換(unbase64を使用)する
  3. Binaryに変換された各要素をデコードしStringに変換(decodeを使用)する
  4. 最後に各要素のStringを連結(concatを使用)する

以下が上記流れを踏んだ完成形のクエリです:

完成形のクエリ

select concat(
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[0])>0 then split(subject,'=\\?UTF-8\\?B\\?')[0] else '' end,
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[1])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[1]),'UTF-8') else '' end,
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[2])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[2]),'UTF-8') else '' end
    ) as decoded_subject
  from email_table

次のセクションでどのようにして上記クエリにたどり着いたか解説します。

デコードしてみる

それでは、実際にMIMEエンコードされたデータを上記のデコードしていきましょう。Hive上にあるテーブル(「email_log」とします)の「subject」というカラムに以下のようなString型のデータが格納されている前提で、上記流れに従ってデコードをします。

=?UTF-8?B?55m76Yyy44GX44Gf44Oh44O844Or44Ki44OJ44Os44K544KS56K66KqN44GX?= =?UTF-8?B?44Gm44GP44Gg44GV44GE?=
  1. まずsplitで「=?UTF-8?B?」という文字列で区切って分割します
hive> select split(subject,'=\\?UTF-8\\?B\\?') 
        from email_log;
+--------------------------------------------------------------------------------------------+
|split(subject, =\?UTF-8\?B\?, -1)                                                           |
+--------------------------------------------------------------------------------------------+
|[, 55m76Yyy44GX44Gf44Oh44O844Or44Ki44OJ44Os44K544KS56K66KqN44GX?= , 44Gm44GP44Gg44GV44GE?=] |
+--------------------------------------------------------------------------------------------+
  • 0番目の要素: Null
  • 1番目の要素: 55m76Yyy44GX44Gf44Oh44O844Or44Ki44OJ44Os44K544KS56K66KqN44GX?=
  • 2番目の要素: 44Gm44GP44Gg44GV44GE?=
  1. 配列の各要素(本例では1要素目と2要素目)にはBase64エンコードされた文字列がセットされているので、unbase64でBase64エンコードされた文字列をBinaryに変換します
hive> select unbase64( split(subject,'=\\?UTF-8\\?B\\?')[1] ),
             unbase64( split(subject,'=\\?UTF-8\\?B\\?')[2] )
        from email_log;
+----------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------+
|unbase64(split(subject, =\?UTF-8\?B\?, -1)[1])                                                                                          |unbase64(split(subject, =\?UTF-8\?B\?, -1)[2])                                                               |
+----------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------+
|[E7 99 BB E9 8C B2 E3 81 97 E3 81 9F E3 83 A1 E3 83 BC E3 83 AB E3 82 A2 E3 83 89 E3 83 AC E3 82 B9 E3 82 92 E7 A2 BA E8 AA 8D E3 81 97]|[E3 81 A6 E3 81 8F E3 81 A0 E3 81 95 E3 81 84]                                                               |
+----------------------------------------------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------+
  1. decodeで(UTF-8をcharsetとして指定)してBinaryをStringへと変換します
hive> select decode( unbase64(split(subject,'=\\?UTF-8\\?B\\?')[1]),'UTF-8' ),
             decode( unbase64(split(subject,'=\\?UTF-8\\?B\\?')[2]),'UTF-8' )
        from email_log;
+-------------------------------------------------------------+-------------------------------------------------------------+
|decode(unbase64(split(subject, =\?UTF-8\?B\?, -1)[1]), UTF-8)|decode(unbase64(split(subject, =\?UTF-8\?B\?, -1)[2]), UTF-8)|
+-------------------------------------------------------------+-------------------------------------------------------------+
|登録したメールアドレスを確認し                                 |てください                                                   |
+-------------------------------------------------------------+-------------------------------------------------------------+
  1. 配列の1要素目と2要素目の文字列(3でMIMEデコードされた状態)をconcatで連結します
hive> select concat(
             decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[1]),'UTF-8'),
             decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[2]),'UTF-8')
             ) as decoded_subject
        from email_log;
+------------------------------------------+
|decoded_subject                           |
+------------------------------------------+
|登録したメールアドレスを確認してください     |
+------------------------------------------+

これでデコードができましたね!

ちなみに、実データには以下のような英文字だけでそもそもエンコードされてないデータだったり、

Welcome to ABC!

以下のように英文字で始まり途中から=?UTF-8?B?でエンコードされているような変化球もありました。

ABC =?UTF-8?B?44Gu44Ko44Oz44K/44O844OX44Op44Kk44K644ON44OD?= =?UTF-8?B?44OI44Ov44O844Kv44Gr44GU5Y+C5Yqg44GP44Gg44GV44GE?=

このようなデータも考慮し分岐処理を入れると以下のような感じになります(前述の完成形のクエリと同じ)

hive> select concat(
        case when length(split(subject,'=\\?UTF-8\\?B\\?')[0])>0 then split(subject,'=\\?UTF-8\\?B\\?')[0] else '' end,
        case when length(split(subject,'=\\?UTF-8\\?B\\?')[1])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[1]),'UTF-8') else '' end,
        case when length(split(subject,'=\\?UTF-8\\?B\\?')[2])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[2]),'UTF-8') else '' end
      ) as decoded_subject
     from email_log
+---------------------------------------------------+
|decoded_subject                                    |
+---------------------------------------------------+
|登録したメールアドレスを確認してください        |
|Welcome to ABC!                                    |
|ABC のエンタープライズネットワークにご参加ください     |
+---------------------------------------------------+

※0番目の要素は=?UTF-8?B?で始まらない、エンコードされてない文字列なのでデコード処理は不要

ちなみに、上記クエリは=?UTF-8?B?で区切られた要素数が最大3個までという前提になってます。もし件名が長い場合は要素数が3より多くなり、クエリで返される文字列が途切れたものになってしまいます。その場合は、以下のようにN番目の要素までクエリを拡張する必要があります。

select concat(
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[0])>0 then split(subject,'=\\?UTF-8\\?B\\?')[0] else '' end,
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[1])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[1]),'UTF-8') else '' end,
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[2])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[2]),'UTF-8') else '' end,
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[3])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[3]),'UTF-8') else '' end,
       ...
       case when length(split(subject,'=\\?UTF-8\\?B\\?')[N])>0 then decode(unbase64(split(subject,'=\\?UTF-8\\?B\\?')[N]),'UTF-8') else '' end
    ) as decoded_subject
  from email_table

可変長にするクエリが思いつきませんでした。可変長にするいいアイデアがあれば教えてほしいですorz

]]>
<![CDATA[Box CLIの通信をキャプチャーしてみる]]> [Options] と遷移し [Options] ダイアログを開く 2. [HTTPS]のタブを開き、[Capture HTTPS CONNECTs] と [Decrypt HTTP traffic]のチェックを有効化する 3. [Actions]をクリックし、[Export Root Certificate to Deskt]]>https://jikoblog.netlify.app/box-cli-debug-with-fiddler/Ghost__Post__62991dd7e25194000155e3eaTue, 30 Mar 2021 22:28:22 GMTBox CLIの通信をキャプチャーしてみる

Box CLIでコマンドを叩いた際に発生する通信の中身が見たい時、FiddlerのようなHTTPプロキシとして動作する通信デバッグ系のアプリを経由させることによってリクエスト・レスポンスの内容が確認できます。本稿では、設定手順につき記載します。

前提

以下の環境で動かしてます

  • Box CLI: ver 2.6.0(2.xであれば、きっとこちらの手順でいけると思います)
  • Fiddler: v5.0.20204.45441
  • OS: Windows 10(Mac用のコマンドもちょいちょい記載してますが、未検証です)

Fiddler側の設定

Fiddlerを起動して以下の操作を行います。

  1. [Tools] > [Options] と遷移し [Options] ダイアログを開く
Box CLIの通信をキャプチャーしてみる
  1. [HTTPS]のタブを開き、[Capture HTTPS CONNECTs] と [Decrypt HTTP traffic]のチェックを有効化する
  2. [Actions]をクリックし、[Export Root Certificate to Desktop]を選択する(これによって作成されるFiddlerのルート証明書「FiddlerRoot.cer」は後述の手順で使用します)
  3. [Connections]タブを開き、[Fiddler listens on port:]に記載されているポート番号を控えておく(デフォはおそらく8888)
Box CLIの通信をキャプチャーしてみる

以上で、Fiddler側の設定は完了です。

Box CLI側の設定

Box CLI側でプロキシを設定します。GitHubのリリースノートによると、Box CLI ver2.6.0からプロキシ対応が導入されたため、こちら以降のバージョンをご利用の場合は、以下のコマンドから使用するプロキシサーバーを指定できます。

box configure:settings --proxy-url=https://your_proxy_server:proxy_port

今回の例では、ローカルホスト(127.0.0.1)で起動しているFiddler(↑の手順#4のポート番号でListen中)をプロキシとして指定するので、以下のように指定します:

box configure:settings --proxy-url=http://127.0.0.1:8888

ちなみに、以下のコマンドでプロキシのオン・オフが切り替えられます(上の行がオフ、下の行がオン)

box configure:settings --no-enable-proxy
box configure:settings --enable-proxy

なお、Box CLIのバージョンが古い場合は、Windowsでは以下のコマンドで環境変数を設定することで、プロキシ設定を行えます:

Windows (CMD)
set https_proxy=http://127.0.0.1:8888

Windows (Powershell)
$env:https_proxy="http://127.0.0.1:8888"

Mac
export https_proxy=http://127.0.0.1:8888

ここまで設定すると、Box CLIの通信をFiddler経由で行えるようになります。が、この状態でBox CLIのコマンドを叩くと、きっと以下のエラーになります。

C:\Users\user>box users:get me
unable to verify the first certificate

証明書エラーですね。そこで、次の手順が必要になります。

Fiddlerの証明書を信頼する

FiddlerでHTTPS通信を復号するにあたり、Fiddlerのルート証明書を信頼する必要があります。Box CLIはNode.jsをベースにしているため、NODE_EXTRA_CA_CERTSという環境変数を指定することで信頼するルート証明書を追加できるようです。

なお、NODE_EXTRA_CA_CERTS​には、プロキシの認証局 (CA) 証明書 (pem 形式) のファイルの場所を設定する必要があるようで、以下のコマンドで↑の手順#3で作成したFiddlerRoot.cerをpemへと変換します。

openssl x509 -inform der -in FiddlerRoot.cer -out FiddlerRoot.pem

※WindowsにはOpenSSLが標準インストールされてないため、未インストールの場合はインストールが必要になります。こちらのサイトなどが参考になると思います。

その後、以下のコマンドでpemの保存場所をNODE_EXTRA_CA_CERTSにセットします

Windows
set NODE_EXTRA_CA_CERTS=C:\path\to\FiddlerRoot.pem
Windows (Powershell)
$env:NODE_EXTRA_CA_CERTS=C:\path\to\FiddlerRoot.pem
Mac
export NODE_EXTRA_CA_CERTS=/path/to/FiddlerRoot.pem

なお、WindowsのSETコマンドで指定した環境変数はそのセッションのみ有効となるため、コマンドプロンプトを別のウィンドウで開く際は再度設定が必要になります。設定を保持する場合は、以下のように環境変数を追加することで可能となります。

Box CLIの通信をキャプチャーしてみる

Box CLIをFiddler経由で実行する

それでは、Box CLIでコマンドを叩いてみます。

C:\Users\user> box users:get me
Type: user
ID: '12345678'
Name: CLITest
Login: AutomationUser_123456_abcdefg@boxdevedition.com
Created At: '2018-08-13T20:26:19-07:00'
Modified At: '2020-03-11T01:15:34-07:00'
Language: en
Timezone: Asia/Tokyo
Space Amount: 10737418240
Space Used: 0
Max Upload Size: 16106127360
Status: active
Job Title: ''
Phone: ''
Address: ''
Avatar URL: 'https://app.box.com/api/avatar/large/12345678'
Notification Email: []

Fiddlerでリクエスト・レスポンスの中身が見えていればOKです。これで通信のデバッグができますね!

Box CLIの通信をキャプチャーしてみる

参考文献

]]>
<![CDATA[Box + Microsoft Intune MAM without Enrollment を設定してみた]]>https://jikoblog.netlify.app/box-microsoft-intune-mam-without-enrollment/Ghost__Post__62991dd7e25194000155e3e9Mon, 22 Feb 2021 07:50:10 GMTBox + Microsoft Intune MAM without Enrollment を設定してみた

Box + Microsoft Intune MAM without Enrollment を設定してみました。手順や注意点を記載します。
※公式の資料があまり見つからず、個人的な見解も多少混じってますので、間違い等ございましたら、ご指摘いただけますと幸いです。

Box + Microsoft Intune MAM without Enrollment とは

もともとBoxは「Box for EMM」というMDM連携用のアプリを提供していたようですが、「Box for EMM」はMDMへ登録済みのデバイス上でしか(with Enrollmentでしか)利用ができませんでした。

それが以下のリリースノートによると、Intune MAM without Enrollmentに対応したとのことで、MDMへデバイスを登録せずに(without Enrollmentで)、BoxアプリをIntuneの管理下とする(Intune MAMのアプリ保護ポリシーの対象とする)ことが可能になったようです。

https://support.box.com/hc/ja/articles/360057142753-AndroidおよびiOS向けIntune-MAM-without-Enrollment

MDMの管理下へデバイスを登録するということは、MDM管理者がデバイスに対してリモートロックやリモートワイプといった操作がかけられるということになるので、個人が所有しているデバイスを業務で活用するBYODでの利用はハードルが高いと思います(誰だって勝手に初期化されかねない状況に自分のデバイスを置きたくないですよね)。

Intune MAM without Enrollmentでは、MDMにデバイスを登録せずにMAMのアプリ保護機能を使えるので、企業に関連するアプリのみMAMで制限をかけ、プライベート領域と切り離して管理ができます。よって、BYODに向いているといえるのだと思います。

それでは、設定手順に移りたいと思います。

Microsoft Intune側の設定

まず、Microsoft Endpoint ManagerからIntune MAM機能をモバイルアプリ(Box)に対して有効化する設定を行います。以下のMicrosoft社のドキュメント通りに設定を行います。https://docs.microsoft.com/ja-jp/mem/intune/apps/app-protection-policies#create-an-iosipados-or-android-app-protection-policy

  1. Microsoft Endpoint Manager 管理センターにサインインする。
  2. [アプリ] > [アプリ保護ポリシー]と遷移し、[ポリシーの作成]をクリックする。
  3. ポリシーの対象とするOSを選択する。iOSの場合は[iOS/iPadOS]、Androidの場合は[Android]を選択する。
Box + Microsoft Intune MAM without Enrollment を設定してみた
  1. [ポリシーの作成]ウィンドウが開かれるので、ポリシーに任意の名前を付ける。
  2. [アプリ]にて[パブリックアプリの選択]より[Box – Cloud Content Management]を選択する。
    ※[Box for EMM]を選ばないこと!
Box + Microsoft Intune MAM without Enrollment を設定してみた
  1. [データ保護]、[アクセス要件]、[条件付き起動]を以下の記事を参考に自身の要件に沿って設定する。
  1. [割り当て]で、ポリシーの対象とするグループを選択する(ポリシーの対象になっていないユーザーはBoxモバイルアプリにログインできなくなります!)。
  2. [確認および作成]で、設定の内容をレビューし[作成]を押下してポリシーを保存する。

ここまででMicrosoft Intune側の設定は完了です。

Box側の設定

Boxモバイルアプリにユーザーがログインを行う際に、Boxモバイルアプリに対してIntune MAMが適用されるように設定を行います。

  1. Box管理者としてログインし管理コンソールを開く。
  2. [Enterprise設定] > [モバイル] と遷移する。
  3. [Intuneモバイルアプリケーション管理 (Intune MAM) を有効化する]のトグルを有効化する。
Box + Microsoft Intune MAM without Enrollment を設定してみた

Box側の設定は以上です。上記設定を行うことで、所属ユーザーがBoxモバイルアプリでログインを行う際に、Intune MAMへのEnrollを促す画面へと遷移する動作となるようです。

iOS/iPadOSでBoxを使ってみる

iPhone(MDMに未登録)にてアプリストアからBoxをインストールしてログインしてみます。

Box + Microsoft Intune MAM without Enrollment を設定してみた

ログイン画面よりBoxアカウントで認証を完了すると、以下のような画面が表示されます。

Box + Microsoft Intune MAM without Enrollment を設定してみた

[Enroll in Intune MAM]を選択すると、Microsoftアカウントの認証ページに飛ばされます。

Box + Microsoft Intune MAM without Enrollment を設定してみた

Microsoftアカウントで認証を済ませると、Boxモバイルアプリが組織によって管理されている旨のメッセージが表示されアプリの再起動を促されます。

Box + Microsoft Intune MAM without Enrollment を設定してみた

これでiPhoneをMDMに登録することなく、BoxモバイルアプリだけをIntuneの管理下とすることができました!

AndroidでBoxを使ってみる

Android(MDMに未登録)にてGoogle Play ストアからBoxをインストールしてログインしてみます。

Box + Microsoft Intune MAM without Enrollment を設定してみた

ログイン画面よりBoxアカウントで認証を完了すると、Google Playストアが開き[Intune Company Portal]アプリをインストールするよう促されます。

Box + Microsoft Intune MAM without Enrollment を設定してみた

[Intune Company Portal]アプリをインストール後、Boxアプリを開きなおすと、Microsoftアカウントで認証するよう促されます。
※[Intune Company Portal]アプリ内でのログインは不要です(ただインストールすることは必須だそうです。Ref: https://docs.microsoft.com/ja-jp/mem/intune/apps/mam-faq#app-experience-on-android

Box + Microsoft Intune MAM without Enrollment を設定してみた

Microsoftアカウントで認証後、以下のような画面になりBoxアプリがIntuneの管理下となっていることがわかります。

Box + Microsoft Intune MAM without Enrollment を設定してみた

注意点

Boxへのログインに使用するアカウントのメールアドレスとMicrosoft Intune側のアカウントのメールアドレスは一致していないとログインができないようです。異なるメールアドレスを使用した場合、Intuneアカウントでログインしようとした際にエラーになりました。

iOSのエラー
Box + Microsoft Intune MAM without Enrollment を設定してみた
Androidのエラー
Box + Microsoft Intune MAM without Enrollment を設定してみた
]]>
<![CDATA[Googleモバイルフレンドリーテストで表示が崩れる]]>https://jikoblog.netlify.app/google-mobile-friendly-test/Ghost__Post__62991dd7e25194000155e3e8Tue, 22 Dec 2020 06:36:58 GMTGoogleモバイルフレンドリーテストで表示が崩れる

スマホでページを閲覧するときは問題ないのに、Googleのモバイルフレンドリーテストでページをレンダリングするときはなぜか表示が崩れて、モバイルフレンドリーテストがFailしてました。解決方法につき記載します。

事象

Googleのモバイルフレンドリーテストはモバイルデバイスでのページの使いやすさをテストするツールです。昨今よりGoogleではスマートフォンクローラが使用されているようで、このテストがこけているとSEOで検索下位に表示されたり、無視されてインデックスすらされないこともあるようで、非常に重要な問題です。

モバイル端末からページを開く際に表示が崩れてなければ特に問題ないと思ってました。が、なぜかモバイルフレンドリーテストがFailしてました。テストだと以下のようにページがレンダリングされており、確かに表示が崩れております。

Googleモバイルフレンドリーテストで表示が崩れる
Googleモバイルフレンドリーテストを実行時

でも、スマホで見ると特に問題はないのです。はて???

Googleモバイルフレンドリーテストで表示が崩れる
スマホから閲覧した場合

原因

「ページの読み込みに関する問題」の「詳細を表示」すると原因が見えてきました。どうやらスタイリングに使用するcssjsといったスタティックアセットがテストの際に読み込まれてなかったようです。

Googleモバイルフレンドリーテストで表示が崩れる

ステータスの列に「Googlebotがrobots.txtによってブロックされています」と記載されております。robots.txtとは、サイト内でクローラ(Googleなどサーチエンジンの)に収集されたくないコンテンツを指定できるファイルです。私の場合は、以下のように記述しておりました。

robots.txt
# global
User-agent: *
Disallow: /cgi-bin/
Disallow: /wp/wp-admin/
Disallow: /wp/wp-includes/
Disallow: /app/plugins/
Disallow: /app/mu-plugins/
Disallow: /app/cache/
Disallow: /app/themes/
Allow: /app/uploads/

WordPressで使用しているテーマのcssjsが格納されている/app/plugins/配下がクロールのDisallow(禁止)対象とする記述になっておりました。

よって、モバイル端末から閲覧した際には問題がないものの、モバイルフレンドリーテスト(クローラ)がアクセスしたときだけ表示崩れが発生しておりました。

解決方法

以下をrobots.txtに追記することで解決しました。

User-Agent: Googlebot
Allow: .js
Allow: .css

Googlebotに対しては、.js.cssはどこのパスにあってもクロールをAllow(許可)するという指定方法です。

robots.txt(変更後)
# global
User-agent: *
Disallow: /cgi-bin/
Disallow: /wp/wp-admin/
Disallow: /wp/wp-includes/
Disallow: /app/plugins/
Disallow: /app/mu-plugins/
Disallow: /app/cache/
Disallow: /app/themes/
Allow: /app/uploads/

# For allowing access to site from mobile friendly test
User-Agent: Googlebot
Allow: .js
Allow: .css

上記にて自身のサーバー上のrobots.txtを更新した後、Googleのrobots.txtテスターツールを開き「送信」を押し更新をGoogleに通知することで、Googleに最新のrobots.txtを取得してもらいます。

その後、先ほどモバイルフレンドリーではありませんと判定されたページを再びモバイルフレンドリーテストにかけると、無事Passすることができました!

]]>
<![CDATA[WordPressをDocker上でWP-CLIで実行する]]>https://jikoblog.netlify.app/wordpress-wp-cli/Ghost__Post__62991dd7e25194000155e3e7Mon, 14 Dec 2020 07:57:53 GMTWordPressをDocker上でWP-CLIで実行する

WordPressのローカル開発環境の手段として、WP-CLI(WordPressを管理するためのコマンドラインツール)をDocker Desktop上で実行しWordPressを動かす方法を取ってみました。手順を書き残しておきます。

利用環境

私が利用した開発環境は以下になります。

  • Windows 10(WordPressはDocker上で動かすのでホストOS依存しないと思います)
  • wordpress-herokuのプロジェクトを利用

wordpress-herokuとはBedrockをベースにしたWordPressをHeroku上で動かすことを楽ちんにしてくれるプロジェクトです。

この手法を取った背景

そもそもwordpress-herokuプロジェクトはローカル環境でもWordPressを動かすための手順を用意しており、こちらのWikiに記載されております。

にもかかわらず、なぜわざわざDocker上で動かすのかというと、RedisやMySQLもローカル用に環境を用意したいってなった時に楽そうかな、と思ったのがまず一点。

そして、大きな理由としては、Windows上で手順通りにWordPressを動かしてみた(以下のコマンドを実行)ものの、なんか動作が怪しかったという。。。

php wp-cli.phar server --host=0.0.0.0 --port=80 --path=web

自身で追加したテーマが使われずデフォのTwenty-Seventeenっぽいテーマが使用されてたり。。

WordPressをDocker上でWP-CLIで実行する

サーバーログにも特に関連がありそうなエラーも見つからず、コードを深く追うことも避けたかったため、実行環境(Windows)の問題なのかな、とDockerで動かしてみたらなんと諸々問題が解消されました!

セットアップ方法

さて、前置きが長くなりましたが、セットアップに移りましょう。

wp-cliのDocker用のイメージ(wordpress:cli)が配布されており、そちらを使用してWordPressをDocker上で動かします。

手順は以下になります。

  1. Docker Desktopをインストールします。

URL: https://docs.docker.jp/get-docker.html
※インストール手順はWeb上の各所で記載されており、ここでは割愛します。

  1. プロジェクトフォルダの直下にdocker-compose.ymlを作成します。
docker-compose.yml
version: '3.6'
services:
   cli:
     image: wordpress:cli-2.4.0-php7.4
     volumes:
       - .:/var/www/html
     ports:
       - "80:8080"
     envlog_file: .env
     command: wp server --host=0.0.0.0 --port=8080 --path=web
  1. その後、Dockerを起動した状態で、コマンドプロンプトにて以下のコマンド実行しDockerコンテナが稼働するIPアドレスを確認します。
docker-machine ip
  1. 私の場合は192.168.99.100が返ってきました。そのIPアドレスをプロジェクトフォルダ内の.envファイルに記載します。
.env(変更前)
WP_HOME=http://localhost
WP_SITEURL=${WP_HOME}/wp
.env(変更後)
WP_HOME=http://192.168.99.100
WP_SITEURL=http://192.168.99.100/wp
  1. コマンドプロンプトでプロジェクトフォルダに移動して、以下のコマンドを実行してコンテナをビルドおよび実行します。
docker-compose up
  1. これで準備完了です。Dockerコンテナにhttpでアクセスしてページを開くことができます。

http://192.168.99.100

Appendix

docker-compose.ymlの補足的な説明を書き残しときます。

  • image: 現時点で一番新しそうなwordpress:cli-2.4.0-php7.4を使用してます。
  • volumes: .:/var/www/htmlと指定し、ホスト側のカレントディレクトリ(プロジェクトフォルダ)をコンテナ側に共有します。これにより、コンテナ側からホスト側にあるWordPressのプロジェクトフォルダにアクセスできます。
  • ports: 外部(コンテナ外)からは80番ポートで接続できるように、8080を80へマッピングしてます。
  • env_file: こちらの手順通り.envファイルを作成し、それが参照されます。
  • command: wp serverコマンドをport=8080で指定して実行してます。port=80でやろうとしたら以下のエラーになったので、80以外で指定が必要なのだと思います。
cli_1  | [Sun Dec 13 12:30:30 2020] Failed to listen on 0.0.0.0:80 (reason: Permission denied)
]]>
<![CDATA[Herokuで"at=error code=H14 desc=No web processes running"エラーになる件]]>https://jikoblog.netlify.app/heroku-at-error-code-h14-desc-no-web-processes-running/Ghost__Post__62991dd7e25194000155e3e6Fri, 11 Dec 2020 08:55:23 GMTHerokuで"at=error code=H14 desc=No web processes running"エラーになる件

HerokuにDockerコンテナ(Webサーバー)をデプロイした際に、"No web processes running"エラーが発生してしまいました。原因や解決方法について調べたので、内容をメモします。

事象

HerokuにDockerコンテナ(Expressを利用したWebサーバー)をデプロイした後、ページを開いてみるとApplication errorが発生しておりました。

サーバーログをheroku logs --tailで確認してみると、以下のように"No web processes running"とのエラーが出力されておりました。

2020-12-06T06:05:22.736018+00:00 heroku&#91;router]: at=error code=H14 desc="No web processes running" method=GET path="/" host=jiko-album-artwork-backend.herokuapp.com request_id=33285f21-ed78-4733-b3d4-1214031f1daa fwd="118.158.162.21" dyno= connect= service= status=503 bytes= protocol=https
2020-12-06T06:05:23.397411+00:00 heroku&#91;router]: at=error code=H14 desc="No web processes running" method=GET path="/favicon.ico" host=jiko-album-artwork-backend.herokuapp.com request_id=39ff37fc-42c9-4f68-aedf-19c1e3cfcc5c fwd="118.158.162.21" dyno= connect= service= status=503 bytes= protocol=https

原因

どうやらDockerコンテナをビルドする際に指定したプロセス名に問題があったようです。

私がデプロイに使用したコマンドは次の通りです。

docker build -t registry.heroku.com/$HEROKU_BACKEND_APP_NAME/express -f ./express/Dockerfile.express ./express;
docker push registry.heroku.com/$HEROKU_BACKEND_APP_NAME/express;
heroku container:release express --app $HEROKU_BACKEND_APP_NAME

こちらの記事を読んだ際、Dockerコンテナをデプロイするにあたり、<process-type>は任意の文字列でいいのかなと思っていたので、”express”を指定しておりました。が、どうやらWebサーバーとして動かすコンテナは”web”と指定しないと動かないようです。

こちらの記事を読んだ際、Dockerコンテナをデプロイするにあたり、<process-type>は任意の文字列でいいのかなと思っていたので、"express"と指定しておりました。が、どうやらWebサーバーとして動かすコンテナは"web"と指定しないと動かないようです。

よくよく調べてみると公式ドキュメントの別のページに、Herokuのプロセスタイプは"Web", "Worker", "One-off"の3種類があり、その中でも"Web"プロセスのみが外部から(HerokuのRouterを経由)のHTTPトラフィックを受信できる、と記載されてますね。つまり、"Web"プロセスがなければ、ページにアクセスしてもトラフィックがデプロイしたWebサーバーに届かずにエラーになるようです。

解決方法

よって、<process-type>を以下のように"web"で指定することで無事ページが開けるようになりました!

docker build -t registry.heroku.com/$HEROKU_BACKEND_APP_NAME/web -f ./express/Dockerfile.express ./express;
docker push registry.heroku.com/$HEROKU_BACKEND_APP_NAME/web;
heroku container:release web --app $HEROKU_BACKEND_APP_NAME

ちなみに、私は上記を実行した後、以下のコマンドも実行してWebプロセスのDynoを手動で立ちあげる必要がありました。

heroku ps:scale web=1

上記は"web"のDynoを1というスケールで実行するコマンドです。Dyno[1]の数を増やすことでスケールアウトできます。


  1. DynoとはHerokuで使用されるコンテナのこと。参考記事 ↩︎

]]>
<![CDATA[TypeScriptチートシート]]>https://jikoblog.netlify.app/typescript-cheat-sheet/Ghost__Post__62991dd7e25194000155e3e5Sun, 06 Dec 2020 13:24:35 GMT

TypeScriptの実行環境の準備

TypeScriptチートシート

TypeScript を始めるために必要なパッケージをインストールする

$ npm install -g typescript ts-node
パッケージ概要
typescriptTypeScriptコンパイラ(トランスパイラ)
ts-nodeTypeScriptのコンパイルと実行を一つのコマンドでできるCLIツール

インストール後は、以下のコマンドを実行してインストールされていることを確認する

$ tsc --version
Version 4.0.3
tscは typescript の短縮名

TypeScriptを実行する

TypeScript のコードを実行してみる

hello.ts
function hello(name: string): void {
  console.log(`Hello ${name}!`);
}

hello('kojimaru');

上記ファイルを用意し、以下のコマンドを実行する

$ tsc hello.ts

するとhello.jsが作成される。hello.jsnode hello.jsで実行できる

$ node hello.js
Hello kojimaru!

もしくはts-nodeを使用することで、コンパイルと実行を同時に行える

$ ts-node hello.ts
Hello kojimaru!
]]>
<![CDATA[FiddlerでBasic認証のプロキシ環境を構築する]]>https://jikoblog.netlify.app/fiddler-basic-authentication/Ghost__Post__62991dd7e25194000155e3e4Tue, 10 Nov 2020 20:06:02 GMTFiddlerでBasic認証のプロキシ環境を構築する

FiddlerはHTTP/HTTPS通信をキャプチャーするツールとして有名ですが、端末のプロキシサーバーとして使用することができ、疑似的なBasic認証の環境を構築できます。FiddlerをBasic認証サーバーとして環境構築する手順をまとめてみました。

設定方法

前提:

手順:

  1. まずBasic認証で使用するためのユーザークレデンシャル(ユーザー名とパスワード)を設定します。ユーザークレデンシャルはbase64エンコードする必要があるので、FiddlerのTextWizardを [Tools] ->
[TextWizard] から開きます。

FiddlerでBasic認証のプロキシ環境を構築する

  1. TextWizardの上段にユーザークレデンシャルを以下の書式で入力します。
<ユーザー名>:<パスワード>

この例では以下で設定してます:

  • ユーザー名: testUser
  • パスワード: testPass
  1. base64エンコードされた文字列がTextWizardの下段に自動入力されるので、その文字列をコピーします。
FiddlerでBasic認証のプロキシ環境を構築する
  1. Fiddlerの [QuickExec] に以下を入力し、エンターを押下します。
prefs set fiddler.proxy.creds <手順3にてbase64エンコードした文字列>

分かりずらいかもしれませんが、QuickExecは画面左下のこちらです。

FiddlerでBasic認証のプロキシ環境を構築する
  1. [Rules] -> [Require Proxy Authentication] を選択し、プロキシ認証を有効化します。
FiddlerでBasic認証のプロキシ環境を構築する

これで準備完了です!

あとは、[File] -> [Capture Traffic] を選択して、通信キャプチャーを有効化した状態で、ブラウザからサイトにアクセスしてみましょう。ブラウザ上でプロキシ認証を通すよう促されます。

FiddlerでBasic認証のプロキシ環境を構築する

手順2で設定したユーザークレデンシャルを入力すると、認証を通しページが見れるようになります!

使用用途

で、ここまで設定手順を書いといてアレですが、いったい何に使うの?という話をします。正直、この機能の使用用途はものすごく限られていると思いますが、私はデスクトップアプリがプロキシのBasic認証に対応しているかの確認に使用しました。

ブラウザに関しては特に気にする必要もないと思いますが、ことデスクトップアプリに関しては、ものによってはプロキシのBasic認証に対応しておらず、プロキシを通した通信が行えないという場合があります(以下は、とあるBasic認証に未対応なアプリで通信した際のアプリログ)。

---> (内部例外 #0) System.Net.Http.HttpRequestException: この要求の送信中にエラーが発生しました。 ---> System.Net.WebException: リモート サーバーがエラーを返しました: (407) プロキシ認証が必要です
   場所 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context)
   場所 System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
   --- 内部例外スタック トレースの終わり ---<---

デスクトップアプリがBasic認証に対応しているか検証するうえで、手っ取り早く環境構築ができる機能になると思いました。

]]>
<![CDATA[Nexus 5X (LG-H791) で楽天アンリミットを試してみた]]>https://jikoblog.netlify.app/rakuten-unlimit-nexus5/Ghost__Post__62991dd7e25194000155e3e2Sun, 13 Sep 2020 17:54:19 GMTNexus 5X (LG-H791) で楽天アンリミットを試してみた

Nexus 5X で楽天アンリミットにつなげるか試してみました。結論から言うと、以下の結果のようにデータ通信は利用できるものの、音声通話/SMSが一部利用できませんでした。

楽天回線エリア
(バンド3)
パートナー回線エリア
(バンド18/26)
データ通信
音声通話/SMS ×[1]

考察

今回使用した Nexus 5X (LG-H791) の仕様は以下の通りです(こちらより一部抜粋):

  • CDMA: 非対応
  • LTE(FDD): B1 / 2 / 3 / 4 / 5 / 7 / 8 / 9 / 17 / 18 / 19 / 20 / 26 / 28
  • VoLTE非対応[2]

楽天回線エリアおよびパートナー回線エリア(au回線)の両方のバンドに端末が対応していることから、データ通信(4G LTE)は使用可能という結果になりました。

※ちなみに、優先ネットワークの設定でLTE Onlyを選択[3]しなければ、4Gにつなぐことができませんでした。

Nexus 5X (LG-H791) で楽天アンリミットを試してみた
隠しコマンド「*#*#4636#*#*」から開いた画面

しかし、音声通話・SMSは回線によって結果が分かれました。端末がVoLTEに対応してないことが原因と推察します。VoLTEが使用できないことで、3Gフォールバックしても、au回線のCDMA 1X WINには端末が非対応でつなぐことができずに、電話回線が利用できないのかもしれません。


  1. Rakuten Link使用により発信のみ可能(データ通信が利用される) ↩︎

  2. おそらくGoogle版の端末のため(こちらの記事によると大手プロバイダー経由で購入すると対応されている模様) ↩︎

  3. 電話アプリから「*#*#4636#*#*」と入力することで開けます(もしくはこちらのようなアプリから開けます) ↩︎

]]>
<![CDATA[Xperia XZs 602SOで楽天アンリミットのパートナー回線が使用できない件]]>https://jikoblog.netlify.app/rakuten-unlimit-xperia/Ghost__Post__62991dd7e25194000155e3e1Mon, 07 Sep 2020 21:23:05 GMT Xperia XZs 602SOで楽天アンリミットのパートナー回線が使用できない件

それは、先日実家に帰省するために下り電車の東海道線に乗って横浜駅を通り過ぎたときのことでした。

あれれ?スマホが4Gにつながらない。。。

いやいや、きっと基地局間でハンドオーバーがうまくいってないだけだよー、って思いましたが、その後も一向に4Gにつながらない。。。

あとで調べてみたら、以下が分かりました。

どうやら、私が使っている端末 Xperia XZs 602SO (2017年にSoftbankより購入)がパートナー回線(au回線)のバンドを受け付けていなかったようです。

Xperia XZs 602SOの対応周波数(4G LTEのみ)

周波数帯バンドXperia XZs対応Note
2.0GHzバンド1Softbank契約時はきっとこれ使ってた
1.7GHzバンド3楽天回線エリア
900MHzバンド8
1.5GHzバンド11
800MHzバンド18/26auプラチナバンド
※楽天パートナー回線エリアはこれ
800MHzバンド19
1.5GHzバンド21
700MHzバンド28
3.5GHzバンド42
出典: https://cdn.softbank.jp/mobile/set/common/pdf/support/usim/unlock_procedure/frequency-band-list.pdf

つまり、楽天回線エリア内ではXperia XZsでも4Gが入るものの、ひとたび楽天回線エリアから出てしまうと、パートナー回線エリアに切り替わり、端末が対応してないことでネットがつながらなくなってしまう、という状況だったようです。

楽天アンリミットのサービスエリア

こちらのエリア図によると、JR東海道線で横浜駅から戸塚駅に向かう途中で、楽天回線エリアから外れ、パートナー回線エリアに切り替わってしまうようです(2020/09/07時点)。

Xperia XZs 602SOで楽天アンリミットのパートナー回線が使用できない件
© Rakuten Mobile, Inc.

5月末に楽天アンリミットを利用開始してから、3か月以上経って今更気付くという。。。住んでる地域が楽天回線エリアで使えちゃってた、かつ昨今の外出自粛で全然遠出してなかった、ことで良くも悪くも全く気付きませんでした。

うーん、でも思い返せば、楽天回線エリア内でも建物の中などバンド3の電波が入りにくい場所では、確かにauローミングされずにただネットがつながらなかったよな。これのせいだったのか!

てっきり端末のSIMロックを解除できれば、どんなSIM入れても使えるのだと思ってましたが、端末がプロバイダーのバンドを受信できるかということも確認しないとダメなんですね。以後、端末の購入やSIMの契約をするときには気を付けないといけないポイントだと思いました。

2022年7月1日スタート予定!Rakuten UN-LIMIT VII(料金プラン) | 楽天モバイル
シンプルなワンプラン「Rakuten UN-LIMIT VII(ラクテンアンリミットセブン)」が2022/ 7/1(金)スタート予定!どれだけ使っても月々2,980円(税込3,278円)使わない月はドンドン安くなる!6/1(水)より先行してスタートキャンペーン開始!他にも楽天市場のお買い物がおトクになったりスマホで楽しめる特典が盛りだくさん!楽天ポイントがザクザク貯まる!※アンリミテッドではありません
Xperia XZs 602SOで楽天アンリミットのパートナー回線が使用できない件
]]>
<![CDATA[Boxのデバイストラストを使ってみた]]>https://jikoblog.netlify.app/configuring-box-device-trust/Ghost__Post__62991dd7e25194000155e3dfSat, 05 Sep 2020 14:32:31 GMTBoxのデバイストラストを使ってみた

Boxの「デバイストラスト」というログイン時に端末認証を行う機能を使用してみました。セットアップしたときに踏んだ手順を書き残しときます。

ログイン端末上に、ルート証明書によって署名されたクライアント証明書が存在しているか確認を行う「オプション1 – デバイス固有の証明書の検証」のセットアップ手順になります。

公式記事はこちら: https://support.box.com/hc/ja/articles/360044194993-デバイストラストのセキュリティ要件の設定

IT管理者側の事前準備

  1. IT管理者がCA(「オレオレ認証局」でOK)にてルート証明書(後の手順で作成するクライアント証明書のルートとなる)を予め作成しておく
openssl genrsa -out MyRootCA.key 2048
openssl req -x509 -new -nodes -key MyRootCA.key -sha256 -days 3650 -out MyRootCA.pem
  1. Boxに管理者アカウントでログインし、管理コンソールに#1で作成した証明書(MyRootCA.pem)をアップロードする

Boxのデバイストラストを使ってみた

クライアント証明書の発行

  1. クライアント側で秘密鍵(MyClient.key)とCSR(MyClient.csr)を発行して、CSRをCA(IT管理者)に提出する
    ※クライアント側と書きましたが、作業自体はルート証明書発行した時と同じ環境で行ってもOK(CA上でクライアント証明書発行作業まで完結できます)
openssl genrsa -out MyClient.key 2048
openssl req -new -key MyClient.key -out MyClient.csr
  1. IT管理者が提出されたCSR(MyClient.csr)をもとに、事前に作成しておいたCAの証明書(MyRootCA.pem)で署名してクライアント証明書(MyClient.pem)を発行する
    ※クライアント証明書(MyClient.pem)がユーザー配布用です。間違って、ルート証明書(MyRootCA.pem)をユーザーに渡さないように!
openssl x509 -req -in MyClient.csr -CA MyRootCA.pem -CAkey MyRootCA.key -CAcreateserial -out MyClient.pem -days 3650 -sha256
  1. クライアント証明書を秘密鍵で署名してPFXを作成し、クライアント端末にインストールする
openssl pkcs12 -inkey MyClient.key -in MyClient.pem -export -out MyClient.pfx

ちなみに、クライアント証明書(MyClient.pfx)のインストール先は、利用しているBox Toolsの種類によって異なるのでご注意を!

Boxのデバイストラストを使ってみた

[会社の証明書の確認] が有効な場合、Box Toolsが実行されているのと同じユーザーコンテキストで使用可能な証明書ストアに証明書をインストールする必要があります。例えば、マシン全般のインストール環境でBox Toolsが実行されている場合、デバイストラストのチェックはSYSTEMユーザーのコンテキストで実行されます。証明書をユーザーの証明書ストアにのみインストールする場合、デバイストラストのチェックが失敗することがあります。デバイストラストを機能させるため、(他の場所に加えて) ローカルマシンのプロファイルに証明書をプッシュする必要があります。

Ref: https://support.box.com/hc/ja/articles/360044194993-デバイストラストのセキュリティ要件の設定

以上でセットアップは完了です。お疲れ様でした!あとはログインの検証をしてみましょうー

出力ファイルおさらい

この手順で作成されるファイルのまとめです。実際に使用するのは以下の2点:

  • ルート証明書(MyRootCA.pem)を管理コンソールにアップロード
  • クライアント証明書(MyClient.pfx)を端末にインストール
Output file Description
MyRootCA.key CAの秘密鍵
MyRootCA.pem ルート(つまり自己署名)証明書
MyClient.key クライアントの秘密鍵
MyClient.csr クライアントのCSR(これをルート証明書で署名する)
MyClient.pem クライアント証明書(ルート証明書によって署名済み)
MyClient.pfx 秘密鍵とクライアント証明書を内包したPKCS#12形式のクライアント証明書ファイル

おまけ

クライアント証明書がルート証明書に署名されているか確認したい場合、opensslのサブコマンドverifyで検証できます。

openssl verify -CAfile ルート証明書 クライアント証明書
成功例
$ openssl verify -CAfile MyRootCA.pem MyClient.pem
MyClient.pem: OK
失敗例
$ openssl verify -CAfile MyRootCA.pem MyAnotherClient.pem
MyAnotherClient.pem: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
error 18 at 0 depth lookup:self signed certificate
OK
]]>
<![CDATA[BIGINT(20) unsignedの桁数について]]> desc wp_table; +-------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------------------+------+-----+---------+----------------+ | id | bigint(20) unsigned | NO | PRI | NULL | auto_incremen]]>https://jikoblog.netlify.app/mysql-bigint-unsigned/Ghost__Post__62991dd7e25194000155e3deWed, 02 Sep 2020 21:29:51 GMTBIGINT(20) unsignedの桁数について

BIGINT(20) unsignedというMySQLのデータ型が何桁まで表現できるのか調べてみました。このデータをString型の変数に代入するときに何文字になるのか気になったのが発端です。

カッコ内の数値は表示幅

MySQLデータベースを触っていて、ふととあるデータ型について疑問に思ったので、調べてみた。まず、こちらのテーブルのidというキーのデータ型をご覧いただきたい。

db> desc wp_table;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type                | Null | Key | Default | Extra          |
+-------+---------------------+------+-----+---------+----------------+
| id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
+-------+---------------------+------+-----+---------+----------------+

私の素朴な疑問としては、BIGINT(20) unsignedって結局何ケタになるの?

BIGINTは264(8バイト)通りの数値を表せる。十進数に置き換えると、

  • signed BIGINTであれば-263~263-1、または -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
  • unsigned BIGINTであれば、0~263-1、または 0 ~ 1,844,674,407,370,955,161

の範囲が表現可能ということになるが、ではカッコ内の「20」は一体何なの?

ってことで、調べたところ、公式ドキュメントに以下のような記載がありました!

M は整数型の最大表示幅を示します。最大表示幅は 255 です。セクション11.2「数値型」で説明しているように、表示幅はその型に含めることができる値の範囲とは関係ありません。浮動小数点型と固定小数点型の場合、M は格納可能な桁数の合計です。

https://dev.mysql.com/doc/refman/5.6/ja/numeric-type-overview.html

どうやら、このカッコ内の数値 M(私の例では20)は最大表示幅を示しており(使用可能な値の範囲とは関係ない)、ZEROFILLオプションを利用している際に、ゼロ埋めを何ケタまで行うかのケタ数を指定するものらしい。

例えば、INT(5)のデータ型を持つテーブルに123という3ケタのデータがある場合、00123という感じに5ケタになるようにゼロ埋めしてくれる幅のサイズを示しているとのこと。

また、この定義はZEROFILL機能に対して使用される機能であり、値の上限を示すものではないとのこと。よって、INT(5)に123456のような6ケタの値も格納可能。

ちなみに、こちらのStack Overflowの記事で分かりやすく説明してくれてる方がいらっしゃいました。
https://stackoverflow.com/questions/3135804/types-in-mysql-bigint20-vs-int20#answer-3135854

]]>
<![CDATA[ExcelでUnixtimeを日付に変換]]>https://jikoblog.netlify.app/converting-unixtime-on-excel/Ghost__Post__62991dd7e25194000155e3ddSun, 30 Aug 2020 19:28:27 GMTExcelでUnixtimeを日付に変換

ExcelでUnixtime(ユニックスタイム)を日付に変換する方法について紹介します。ウェブ検索で見つけた数式を何も考えずにそのまま使ったらうまくいかなかったので、方法だけでなく仕組みや注意点についても備忘録的に書き残しておこうと思います。

Unixtimeとは

この記事を読んでいる方は、Unixtimeとは何かご存知の上でここにたどり着いたのだと思いますが、結構重要なポイントがあるので見てみましょう。

Unixtimeとは、一言でいうとこういうやつです。

1598253617

そう、Unixtimeとは1970-01-01 00:00:00 (GMT)から何秒経過したかを示しています。よって、その秒数から日付を算出する計算式を組めば我々人間が直感的に理解できる日付の表示に変換できます。

そして、重要なポイントが2つあります。

  1. UnixtimeはGMTなので、日本時間が知りたい場合は時差を考慮する必要がある
  2. Unixtimeは上の例のように10ケタとは限らずデータ型によっては13ケタや16ケタだったりする(ケタ数が増えるほど精度が良く、13ケタはミリ秒単位、16ケタはマイクロ秒単位となります)。

ちなみに、ネットで私が見つけた記事の多くはUnixtimeが10桁を前提としているようで、私の場合はお恥ずかしい話、桁数の違いのせいで計算がくるってしまいよくわからない値が出てちょっとばかりはまってしまいました。。。ので、これを書いてます!

Excelで変換してみる

では、Excelを使って変換する手順についてみていきたいと思います。

Excelでは、日付は1900年1月1日を1とするシリアル値によって管理されてます(1日ずつ連番で、1900年1月2日は2になります)。
また、前述の通りUnixtimeは1970-01-01 00:00:00 (GMT)から何秒経過したかを示してます。

以上より、Unixtimeを1日あたりの秒数(24*60*60)で割ることで1970年1月1日から経過した時間を秒単位ではなく日単位で取得し、1970年1月1日のシリアル値(25569)に足すことでExcel上で日付として使用できる値を取得できます。

これを数式にしたのがこちらになります

= A1/(24*60*60) + DATE(1970,1,1)
  • A1のセルにunixtimeが入力されている想定
  • DATE(1970,1,1)はシリアル値「25569」を返す

ExcelでUnixtimeを日付に変換

上記は、Unixtimeが10桁であることを想定した式になります。Unixtimeが13桁の場合はミリ秒単位の数値になるため、Unixtimeを1日あたりのミリ秒数(1000*24*60*60)で割ることで、ミリ秒単位を日単位に変換し、1970年1月1日にその日数を足すことで変換できます。16桁の場合も同じ原理で計算できます。

13桁の場合
= A1/(1000*24*60*60) + DATE(1970,1,1)
16桁の場合
= A1/(1000*1000*24*60*60) + DATE(1970,1,1)

ちなみに、上記で出した日付はいずれもGMTなので、日本時間を取得するには時差(GMT+9)を考慮する必要があります。

日本時間(GMT+9:00)に変換
= A1/(24*60*60) + DATE(1970,1,1) + TIME(9,0,0)

セルの表示形式を変更する

上の手順の数式を入力後、B1のセルには変換後のシリアル値が返されます。セルの表示形式をデフォルトのままにしていると、以下のように日付ではなくシリアル値で表示されてしまいます。

ExcelでUnixtimeを日付に変換

その場合は、セルを選択し、右クリック > [セルの書式設定] を選択し、以下のダイアログでセルの書式を日付へと変更することで表示を切り替えられます。

ExcelでUnixtimeを日付に変換

私は上のスクショのように、[ユーザー定義]で以下を指定して、秒数まで表示する書式をよく使います。

yyyy/mm/dd h:mm:ss
]]>