vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

Deveropers.IO 2017 WORLD in 大阪に行ってきました

はじめに

9/23に梅田スカイビルで行われた、クラスメソッド社の方々によるDeveropers.IO 2017 WORLD in 大阪に行ってきました。

dev.classmethod.jp

内容は今年7/1に東京で行われた Deveropers.IO 2017 や、
大阪オフィスの方による計4セッションでした。

聞き漏らしたり間違って理解しているところもあるかとは思いますが、
思うままに書き留めておくことにします。
(各セッションの資料は公開してくれるとのことなので、公開された順にリンクを貼っていく予定です)

クラメソの請求を支える技術(サーバーレス編)

受注から納品後の請求処理までのやり取りをIT化したときの流れ、
見直した後の構成などを紹介する内容でした。

正直一番感じたのは、外から見てイケてる会社であっても、
手動だったりこなれていないところというのは残っているものなのだなぁ、ということでした。

どんな会社でも特に表に出づらい社内のやり取りなど、
どうしても置いてきぼりになりがちだとは思いますが、それをガッと大きく変えていけるところは強いなぁ、と感じました。

あと40代の生存戦略の話で、
例えばWebサービスを作るときにAPIやOAuth2.0などの深い知識と技術を身に着けて活躍する専門家になるのか、
それらの技術をパーツとして組み合わせ、糊付けしてWebサービスを作る人になるのかを決めることが大事。

(意訳)という話も印象的でした。

自分はどうしたいだろう。

何でも完璧にこなすスーパーマンになることができれば良いですが、
それはきっと難しい。

じゃあ何を選ぶのか。どうありたいか。

そんなことを考えさせられたセッションでした。

あとしがないOLさんって女性だったんだ…て

基礎からのOAuth2.0

OAuth2.0の解説、というのが内容の中心ですが、
まずは混同されがちな認証と認可の違いについてのお話から。

よくあるTwitterアカウントを使ってサービスの認証を行う、
というのはOAuthで行うことではない、という話。

これらの内容から、ではOAuth2.0は何をするものなのか、
処理の流れ(アカウントトークンの受け渡しなど)について、
ジョークも交えつつ (いや渋谷の女子高生とか本気かもしれませんが) 噛み砕いて解説されていました。

このセッションについては動画、スライドが公開されているため、
もう一度じっくり見返して理解していきたいところです。
(分かりづらかったのではなく、あまりに私の基礎知識がなさすぎた)

www.slideshare.net

www.youtube.com

クラメソのWebサイトを支える技術

Developers.IOブログなどのWebサイトの構成などを、
その特徴や利点などを交えながら紹介されました。

が、ちょっと私の知識が足りなさすぎて理解が追いつかなかったというのが本音のところです。。。

使用されているAWSのサービスなどについては、資料も見ながら一つずつ辿ってみたいです。

dev.classmethod.jp

Alexaで変わる開発、変わらない開発

Amazonによる、Echoなどのスマートスピーカーを操作することができるAlexaの紹介と、
シンプルな内容でAlexaを動作させるライブ開発、という内容でした。

ステートレスであるAWS Lambdaで、ステートフルな会話から必要なコマンドを拾っていく、
というのは確かに工夫が必要でしょうし、
画面に表示がなく、音声のみによる入力・フィードバックするUIもまだこれから、というところでしょう。

以前Umeda.apk(だったはず)で見たGoogle Homeや今回のAlexaなど、
どれか一つくらいは実際にも触ってみたいところ。

Echoは日本で使えるのはまだ先ですよね。。。

Google Homeは年末くらいに日本でも発売するらしいので、こっちを先に試してみても良さそう。

www.lifehacker.jp

あと開発の様子はGoogle HomeもAlexaも似通っているところがあって、
(揃えているのかもしれませんが)やっぱりこういうやり方が現時点では一番なのかな、とも思いました。

あと何より、ライブ開発、ライブコーディングは見てるだけでも緊張感ありすぎでしたwww

おわりに

楽しかったです。

自分の知識が足りなくて理解が追いつかなかったところも正直ありましたが、
そこはそれ。お話されていた内容をキーワードとして、少しずつ調べていきたいと思います。

やっぱり社内の技術的な内容(だけではないけど)を、
外部にも発信していけるというのは強いなぁ、とも感じました。

クラスメソッドの皆様、ありがとうございました!!

Pythonで CSV -> Json を作る(そしてそれをUnityで読み込み)

はじめに

前回に引き続き必要になったのでメモっておきます。

Pythonを使ってCSVとして保存されたファイルを読み込み、Jsonファイルとして出力。
それをUnityで読み込みます。

Pythonを使うことになった理由は単に興味があったからですw

※2017.9.20修正
Pythonのファイル名、データを格納するための Parts クラスでのアトリビュートの宣言方法を修正しました。

CSVを読み込む

まずはCSVを読み込んで、 Parts というクラス(酷い名前なのは気にしない方向で。。。)に格納します。

parts.csv

PartsNo,PartsName,Description,
No.1,Parts1,一つ目のパーツです,
No.2,Parts2,二つ目のパーツです,

parts.py

 # -*- coding: utf-8 -*-
# coding: utf-8
class Parts:
    def __init__(self, parts_no: str, parts_name: str, description: str):
        self.parts_no = parts_no
        self.parts_name = parts_name
        self.description = description

main.py

 # -*- coding: utf-8 -*-
import csv
from parts import Parts


def main():
  # CSVファイルを読み込む.
  with open(f'parts.csv', encoding='utf-8') as csvFile:
    for index, row in enumerate(csv.reader(csvFile)):
        # タイトル行を無視する.
        if index <= 0:
            continue

        # 読み込んだ内容に[]が含まれているためそれを取り除く.
        replace_row = remove_symbols(str(row))
        split_rows = str.split(replace_row, ',')

        # コンマ区切りでSplitした内容をクラスに格納.
        new_parts = Parts(split_rows[0], split_rows[1], split_rows[2])


def remove_symbols(original: str):
    # 読み込んだ内容に[]、半角スペースが含まれているためそれを取り除く.
    remove_left_bracket = str.replace(original, '[', '')
    remove_right_bracket = str.replace(remove_left_bracket, ']', '')
    remove_space = str.replace(remove_right_bracket, ' ', '')
    return remove_space

main()

  • 「with」を使用することで、C#の「using」と同様ファイルの使用が終わったら自動で開放してくれるようになります。
  • 読み込んだ内容は「[‘PartsNo’, ‘PartsName’, ‘Description’, ‘’]」のように [ と ] が含まれるため、それを取り除く必要があります
    (もう少し上手いやり方がありそうな気はしています)。
  • 今回は読み込んだ内容をわざわざクラスに入れる必要はあまりないのですが、形式や文字数に制限がある場合などはクラス格納 -> チェックとした方が良さそうです。

Jsonファイルとして出力

クラスのデータをDictionaryデータとして受け取る

このままクラスをJsonに変換できると良いのですが(C#Javaのように)、
Pythonでは難しいようです。

そのため、クラスとして格納したデータを受け取って、Dictionaryとして返すようにします。

parts_dictionary_factory.py

 # -*- coding: utf-8 -*-
from parts import Parts


class PartsDictionaryFactory:

    def create(self, target_parts: Parts):
        if type(target_parts) != Parts:
            return

        return {"PartsNo": target_parts.parts_no, "PartsName": target_parts.parts_name,
                "Description": target_parts.description}

main.py

 # -*- coding: utf-8 -*-
import csv
from parts import Parts
from parts_dictionary_factory import PartsDictionaryFactory


def main():
    parts_dictionary = []
    dictionary_creator = PartsDictionaryFactory()

    with open(f'parts.csv', encoding='utf-8') as csvFile:
        for index, row in enumerate(csv.reader(csvFile)):
            if index <= 0:
                continue
            replace_row = remove_brackets(str(row))
            split_rows = str.split(replace_row, ',')
            new_parts = Parts(split_rows[0], split_rows[1], split_rows[2])

            # Dictionaryのデータに変換したものをDictionaryに追加.
            parts_dictionary.append(dictionary_creator.create(new_parts))

~省略~

Jsonファイルの出力

あとはこれまで取得・変換した文字列をJsonに置き換えて、 ファイルとして出力するだけです。

main.py

# -*- coding: utf-8 -*-
import json
import csv
from parts import Parts
from parts_dictionary_factory import PartsDictionaryFactory


def main():
    parts_dictionary = []
    dictionary_creator = PartsDictionaryFactory()

    with open(f'parts.csv', encoding='utf-8') as csvFile:

        for index, row in enumerate(csv.reader(csvFile)):
            if index <= 0:
                continue
            replace_row = remove_symbols(str(row))
            split_rows = str.split(replace_row, ',')
            new_parts = Parts(split_rows[0], split_rows[1], split_rows[2])
            parts_dictionary.append(dictionary_creator.create(new_parts))

    meta_parts = {"ModelName": "Model1", "PartsList": parts_dictionary}

    # 文字列をJson形式に変換.
    json_text = json.dumps(meta_parts)

    # ファイル出力.
    with open(f'parts.json', 'w') as file_object:
        file_object.write(json_text)
        file_object.flush()


def remove_symbols(original: str):
    remove_left_bracket = str.replace(original, '[', '')
    remove_right_bracket = str.replace(remove_left_bracket, ']', '')
    remove_space = str.replace(remove_right_bracket, ' ', '')
    return remove_space


main()

結果として下記のようなファイルが作成されます。

parts.json

{
  "ModelName": "Model1",
  "PartsList": [
    {
      "PartsNo": "'No.1'",
      "PartsName": "'Parts1'",
      "Description": "'\u4e00\u3064\u76ee\u306e\u30d1\u30fc\u30c4\u3067\u3059'"
    },
    {
      "PartsNo": "'No.2'",
      "PartsName": "'Parts2'",
      "Description": "'\u4e8c\u3064\u76ee\u306e\u30d1\u30fc\u30c4\u3067\u3059'"
    }
  ]
}
  • 実際は改行されずに出力されますが、見やすさのために編集しています。

UnityでJsonファイルを読み込む

UnityでJsonのデータをクラスに格納するのは以前もやりましたが、
今回もJsonUtilityを使用します。

まずはJsonのデータを格納するクラスの準備から。

今回はJsonの中に配列(PythonでDictionaryとして出力したもの)が含まれており、
これを格納する Parts というクラスと、
Parts のリスト、及びメタ情報(ModelName)を格納する MetaParts というクラスを作成します。
(名前の酷さはry)

Parts.cs

using System;

[Serializable]
public class Parts
{
    public string PartsNo;
    public string PartsName;
    public string Description;
}

MetaParts.cs

using System;
using System.Collections.Generic;

[Serializable]
public class MetaParts
{
    public string ModelName;
    public List PartsList;
}
  • Jsonのデータを格納するクラスには [Serializable] をつけておく必要があり、
    これがないとうまくデータを格納できませんでした。

ファイルの読み込みとJsonデータからの変換

あとはJsonファイルを読み込み、クラスに格納します。
JsonファイルはUnityEditorで動かす場合は Assets フォルダ直下、Windowsで出力した場合は プロジェクト名_Data フォルダの直下に置きます。

FileLoader.cs

using System.IO;
using System.Text;
using UnityEngine;

public class FileLoader
{
    private readonly string filePath;
    public FileLoader()
    {
        filePath = Application.dataPath + @"/parts.json";
    }
    public MetaParts LoadFromJson()
    {
        if (File.Exists(filePath))
        {
      // ファイルの読み込み.
            using (var reader = new StreamReader(filePath, Encoding.UTF8))
            {
        // ファイルの内容は一括で読み込む.
                var readText = reader.ReadToEnd();
                if (readText.Length > 0)
                {
          // Jsonからの変換に関するエラーチェックは省略.
                    return JsonUtility.FromJson(readText);
                }
            }
        }
        return new MetaParts();
    }
}

あとはこのクラスを読んであげればOKです。

終わりに

Pythonを使うことで、さらっと処理が書けるのは良いと感じます。

ただ、C#でやるように常に型を意識して書きたいのならちょっと厳しいかもしれませんね。

その辺り、Pythonならではの便利なやり方というものがあると思うので、
それを身につけられたらな、と思います。

参照

Python

Unity

【Windows】Unityでコマンドライン引数の受け渡し

はじめに

ちょっと必要になったので。

UnityでWindows用に出力したexeファイルを開くときに、 合わせて引数となる文字列を受け取る(コマンドライン引数)ことで起動後の処理を変える方法。

そしてコマンドライン引数を指定してアプリを開く方法についてまとめます。

コマンドライン引数を受け取る

コマンドライン引数を受け取るには、ズバリ「System.Environment.GetCommandLineArgs()」を使います。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainController : MonoBehaviour
{
    public Text ResultText;
    private void Start () {
        var args = System.Environment.GetCommandLineArgs();
        var resultString = "";

        for (var i = 0; i < args.Length; i++)
        {
            resultString += i.ToString();
            resultString += ": ";
            resultString += args[i];
            resultString += ", ";
        }
        ResultText.text = resultString;
    }
}

配列の0番目にはexeファイルのパスが入り、1番目以降にコマンドライン引数が入ります。

またコマンドライン引数は半角スペースで区切られます。

コマンドライン引数を送る

「System.Diagnostics.Process」を使って別のアプリを開きます。

その際、コマンドライン引数を指定することができます。

using System.Diagnostics;
using UnityEngine;
using UnityEngine.UI;

public class MainController : MonoBehaviour
{
    public Button OpenProcessButton;
    private void Start () {
        OpenProcessButton.onClick.AddListener(() =>
        {
            var process = new Process
            {
                StartInfo =
                {
                    FileName = @"C:\Users\{{Exeファイルのパス}}\GetCommandlineArgs.exe",
                    Arguments = "arg arg2"
                }
            };
            process.Start();

        });
    }
}

上記のように引数を半角スペースで区切ると、受け取る側では2つの引数として認識されます。

参照

初心者(含む非開発者)向けGitによるバージョン管理資料メモ(Git Bash編)

はじめに

前回 Git GUIであれこれやってみたのですが、
なぜか会社のPCで Git GUI が正しく動かない(ファイルの変更が Rescan 後も Unstaged changes に表示されない)ため、
Git Bash を使って説明することにしました。

ということで、前回の内容をCUIで実行してみる、という内容となります。

準備

バージョン管理対象のプロジェクト作成

  1. バージョン管理対象のファイルを任意の場所に置いたフォルダに入れます。
  2. Git Bashを起動します。
  3. git init を実行します。
  4. 1.のフォルダ内に .git というフォルダが作成されます(表示から隠しファイルを表示する必要あり)。
  5. 4.のフォルダ内にこれから保存していく履歴情報が蓄積されることになります。

ユーザー情報などの登録

以下を実行します。

git config --global user.name "ユーザー名"
git config --global user.email メールアドレス

Commitする

まずはファイルを一つ作成して、バージョン管理してみることにします。

  1. ファイルをプロジェクトフォルダに置きます。
  2. Git Bash で git add . を実行します。
  3. git commmit -m “変更内容” を実行してCommmitします。

  4. 2.で、 . の代わりに特定のファイル名を指定することもできます。

  5. 3.で、 -m “変更内容” をつけない場合、実行後に Commit Message を入力するエディタ(デフォルトではVim? が開きます)。

履歴を見る

保存した内容を見てみます。

git log を実行することで、 Commit した日時や Commit Message を見ることができます。

なお、 git log で表示される履歴が4つ以上ある場合、
下記のような状態になり、そのままでは履歴表示モード?が終了できません。

その場合は q を押すと終了できます。

f:id:mslGt:20170901055427j:plain

また、それぞれの Commit 同士の差分を見るには、別途diffツールを用意する必要がありそうです。

バージョン管理しないフォルダ・ファイル

gitignoreの扱いは前回と同じです。

取り消し

直前のCommitを取り消したい場合

git revert HEAD

指定したCommitを取り消したい場合

例えば下記の一番上の Commit を取り消す場合

git revert 082822cfff3c4be617d01758e91a6722b4b6642d
  • ただし、例えば上から2番目のCommitに対して実行するとエラーとなりました。このような場合はオプションなどをつける必要があるかもしれません。

f:id:mslGt:20170901055451j:plain

2017.9.1 更新
Resetについて追記

Reset の場合は git reset を使います。

git reset --hard 082822cfff3c4be617d01758e91a6722b4b6642d

Branchを作る

Branchを作る

Branch を作成するには、以下を実行します。

git branch Branch名

Branchを切り替える

git checkout Branch名

master にマージする

checkoutして master ブランチに戻したあと、

git merge マージするBranch名

終わりに

やっぱり git を使うのはCUIの方が素直で良い気がしますね。。

参照

初心者(含む非開発者)向けGitによるバージョン管理資料メモ

はじめに

初心者(含む非開発者)の方に向けてGitを使ったバージョン管理のお話をすることになったので、
その資料を作るためのメモです。

目的としてはGitの使い方を覚える、というよりはZIPファイルや別名保存以外にも、
バージョン管理のためのツールを使う方法もあるんだよ~、ということを緩く紹介する感じで。

OSはWindowsが多いため Git For Windows に付属?している Git GUI を使うことにします(ある種これが僕にとっての試練w)。

準備

まずはインストールから。特に必要なければそのまま指示に従って進めればOKかと。

バージョン管理対象のプロジェクト作成

  1. バージョン管理対象のファイルを任意の場所に置いたフォルダに入れます。
  2. Git GUI を起動します。
  3. Create New Repository を選択して、1.のフォルダを指定します。
  4. 1.のフォルダ内に .git というフォルダが作成されます(表示から隠しファイルを表示する必要あり)。
  5. 4.のフォルダ内にこれから保存していく履歴情報が蓄積されることになります。

ユーザー情報などの登録

  1. Git GUI でバージョン管理対象のプロジェクトフォルダを開いた状態で、 Edit > Options を開きます。
  2. 左が今開いているプロジェクトの設定、右が共通(グローバル)の設定です。
  3. それぞれの User Name 、 Email Address を入力します。
  4. Default File Contents Encoding を(そうなっていなければ) utf-8 にします。
  5. ファイルエクスプローラーでバージョン管理対象のプロジェクトフォルダを開いて、右クリック > Git Bash Here でGit Bashを開き、以下を実行します(ファイル名やdiffの文字化け防止)。
git config --global gui.encoding utf-8

f:id:mslGt:20170830022318j:plain

Commitする

まずはファイルを一つ作成して、バージョン管理してみることにします。

  1. ファイルをプロジェクトフォルダに置きます。
  2. Git GUI で Rescan を押して、1.のファイルが Unstaged Changes に表示されたることを確認します。
  3. Stage Changed を押して、2.のファイルが Staged Changes に移動したことを確認します。
  4. Commit Message に変更内容を入力して、 Commit ボタンを押します。

履歴を見る

では保存した内容を見てみます。

今はmasterブランチなので、 Git GUI のメニューの Repository > Visualize master’s History を開きます。

変更内容や入力したメッセージ、変更した人(自分だけですが)の情報などを見ることができます。

変更のたびにCommitしていくことで、情報が溜まっていくことになります。

バージョン管理しないフォルダ・ファイル

プロジェクトのフォルダにバージョン管理しないフォルダ・ファイルが含まれる場合があります。

例えば以下のフォルダ、ファイルをプロジェクトのフォルダに置いて、
これをバージョン管理対象から外してみます。

  • IgnoreDirectory (フォルダ。中に IgnoreText2.txt というファイルを含む)
  • IgnoreText.txt

バージョン管理対象から外すには、下記のような内容で .gitignore というファイルをプロジェクトフォルダ直下に置きます。

.gitignore

IgnoreDirectory/*
IgnoreText.txt

この状態でCommitすると、 .gitignore のみが追加され、
IgnoreDirectory フォルダ、中の IgnoreText2.txt 、及び IgnoreText.txt は無視されます。

Unityプロジェクトの Temp フォルダ( Unity Editor 実行時に一時的に作成されるフォルダ)などは、
保存したりしようとするとエラーになるため、 .gitignore に含めると良いと思います。

取り消し

例えばCommit Messageの入力ミスなどでCommitを取り消したい場合。

先程と同じく Repository > Visualize master’s History から履歴を表示します。

で、取り消したいCommitを選択した状態で右クリック > Revert this commit で取り消すことができます。

過去のCommitを消すことも可能ですが、例えばテキストファイルを追加してCommit > 内容を変更してCommitした状態で、
前者のCommitを取り消そうとすると競合が発生し、エラーとなります。

最新のCommitから順番に戻すなどの作業が必要となります。

このRevertも履歴には残るのですが、完全にCommitを抹消したい場合は、
戻したいCommitを選択して右クリック > Reset master branch to here を選択します。

この時 Soft 、 Mixed 、 Hard が表示されます。

  • Soft: ファイルの変更内容はそのままで、Commitのみが取り消される
  • Mixed: ファイルの変更内容はそのままだが、Commitが取り消されて Stage Changed の状態も Unstage Changedに戻される
  • Hard: 変更内容ファイルも取り消され、Commit前の状態まで戻される

Resetのあとファイルを任意で変更するなどしてCommitを行うと、
それより先のCommitは削除されます。

Branchを作る

例えば比較的規模の大きい変更を試しに実装してみたい場合。

もちろんプロジェクトをまるごとコピー、という方法もあります。

しかし、 Branch を利用することで、履歴を複数に分割することができるため、
もとのファイルを( master に)残しながら変更後の内容をCommitし、
それをマージする、といったことが可能になります。

また、複数人で開発を行う場合、
それぞれの開発環境にブランチを作成して開発 > master にマージする、といったことが可能になります。

Branchを作る

Git GUI のメニュー > Branch > Create から作成が可能です。

Branchを切り替える

Git GUI のメニュー > Branch > Checkout から切り替えが可能です。

なおデフォルトのBranchは master です。

作成した Branch でファイルを変更してCommit > master にブランチを切り替えると、
master には変更が反映されていないことが確認できます。

f:id:mslGt:20170830022350j:plain

masterにマージする

作成したBranch (ここでは Branch1 とします)を master にマージするには、

  1. Branch1 で変更をCommitする
  2. master に切り替えて、 Git GUI のメニュー > Merge > Local Merge から、 Branch1 を選択する

ただし master と Branch1 の両方で同じファイルを変更していると、
競合が発生してエラーになります。

終わりに

とりあえず触りの部分だけ書いてみましたが、
資料を作成しつつ必要に応じて修正・追加する予定です。。。

参照

上海、蘇州に行ってきました

はじめに

8/12〜8/19にかけて上海、蘇州に行ってきました。

大まかなところはTwitterでつぶやいたりInstagramで画像を上げたりしまくったのですが、
それ以外に思ったことだったり、使ったVPNなどについてまとめておくことにします。

シェアサイクルについて

最近の中国絡みのニュースでよく話題になっているものの一つにシェアサイクルがあります。

実際、特に上海では至るところにシェアサイクル用の自転車が置かれていました。

www.instagram.com

使用方法としては、使用前に本体(だいたい鍵のある辺り)につけられたQRコードをアプリで読み取って、
鍵に数字が書かれたプッシュ式のボタンがついているので、それを押して解錠。

使用後はもう一度アプリでQRコードを読み取って終了。

金額は使用時間に対してかけられて、無料のものもある、といった感じのようです。

上海のシェアサイクルはどこでも乗り捨て可能、ということで、道を塞ぐくらい大量に自転車が置かれているところがあったり(´・ω・`)

www.instagram.com

どうしても乗り捨てられる場所には偏りが生じるため、夜間にニーズに合わせて?一部自転車を移動しているようです。

一方蘇州はというと、まだそこまで普及はしていないようで、自転車を見かけることが少なかったように思います。

また、見かけたものはどこでも乗り捨て可能なものではなく、専用の機械が用意されたものでした。

www.instagram.com

蘇州も地下鉄が通ったりどんどん便利になっているので、
今後シェアサイクルも広がっていくのかなぁ、といった感じがしました。

キャッシュレス決済について

もう一つ中国絡みのニュースで話題になっているものといえばャッシュレス決済です(私の中で)。

微信や支付宝を使った支払いにはQRコードを使用するのですが、
これが原因なのか街中至るところでQRコードを見かけました。

支払いができるところも格段に増えていて、
確かに現金無しで生活、というのも可能かもなぁ、と思わせられました。

www.instagram.com

ただキャッシュレス生活がそこまで便利かと言われると、正直まだ賛成しかねるところはあります。

支払いの時に支払い方法(微信なのか支付宝なのかなど)を伝えないといけなかったり、
レストランでの食事のとき、現金だとテーブルでそのまま支払い可能なものが(中国のレストランではレジではなくテーブルで支払うことが多いです)レジまで行かないといけなかったり。

この辺りは次回私が中国へ行く頃には解消されているのかもな〜、といった感じです。

あと現状で言うと、現金決済からキャッシュレス決済に移行している、というよりは現金決済に新しい決済方法が加わっている、といった印象を受けました。 (決済方法が増える方が便利になるので、消費者側としては良いことだと思います)

もう一つ、少し気になっているのが、ネットの記事などを見ていると、ホームレスがキャッシュレス決済での支払いに対応しているみたいな話がありますが、
セキュリティ的な危険はないのかなぁ、というところです。

せいぜい言った金額より多く取られるとかそれくらいで、あとはキャッシュレス決済のサービス提供側が安全にやり取りしてくれる感じなのでしょうか。

微信での支払いは、次回中国へ行くときには自分でも使ってみたいところです。

VPNについて

いつも中国へ行くと、TwitterGoogleのサービスが使えず大変厳しい気持ちになるのですが、
今回はVPNを試してみることにしました。

やっぱりGFWには皆困っているようで、VPNも結構種類がありましたが、
2017年のVPNのランキングで上位3位内に入っていて、Paypalが使えて、Linux版にも対応しているというExpressVPNというものにしました。

www.expressvpn.com

あと一ヶ月単位でライセンスを購入できるのも良いですね。

まぁ結局Linux版はやり方がまずかったのかうまく動作させられませんでしたが。。。
(インストール自体は問題なさそうでしたが、接続に失敗していました)

Androidについて言えば、時々つながりにくくなることはあったものの、特に問題なく接続できました。

多分つながりにくくなったのはGFWパワーのせいかと(; ・`ω・´)

VPNとGFWはいたちごっこ的なところはあるわけですが、次回中国に行くときも使えてそうなら、
またExpressVPNを使おうかな〜、という感じです。

おわりに

上海へ行くたびに思うのは、思うよりも変わっているけど思ったよりも変わってない、ということです。

ネットの記事などを見ていると、中国は日本より遥かに先を行っていてもう追いつけないみたいな気持ちにもなりますが、
そういう側面もあるけれども全てがそうでもない、とも思います。

それぞれ状況が違うわけで、そんな簡単には比較できないのではないでしょうか。

ということで、中国を見下すとか崇拝するとかではなく、良いところをどんどん取り入れて進歩していく、というのが良いのではないかな〜、というのが私の感想でした。

主語がでかくてすみませんm( )m

Angularのセキュリティ対策について調べてみる その4

はじめに

続きです。

特定のURLでCSRF(XSRF)対策を無効にする方法、ドキュメントのCross-site script inclusion (XSSI)について追いかけてみました。

特定のURLでCSRF対策を無効にする

前回は全ページでログインしていないとPostリクエストが送れない状態でしたが、
これでは少し不便ですね。

基本的にCSRFの対策はアカウントのパスワード変更など、ログインした状態で行う処理に対して実行するもの、
ということを考えると、例えばログインしていなくても送信したい情報がある場合、
そのページではCSRFを無効にして未ログイン状態でもPostリクエストを送信できるようにする必要があります。

http.csrf().disable()を使う(失敗)

下記のように「http.csrf().disable()」を使ってCSRF対策を無効にしようとすると、 全ページで無効になったり、「http.csrf().disable()」が無視されてしまいます。

WebSecurityConfig.java

〜省略〜
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    〜省略〜
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().and()
                .authorizeRequests()
                .antMatchers("/menulist").authenticated()
                .and().formLogin()
                .and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and().exceptionHandling()
                .accessDeniedPage("/accessdenied.html");

        http
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .and().csrf()
                .disable();
    }
    
}

http.csrf().ignoringAntMatchers()

じゃあどうするか、というと、「http.csrf().ignoringAntMatchers()」を使用します。

WebSecurityConfig.java

〜省略〜
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    〜省略〜
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .httpBasic().and()
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/menulist").authenticated()
                .and().formLogin()
                .and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and().exceptionHandling()
                .accessDeniedPage("/accessdenied.html");

        http
                .csrf()
                .ignoringAntMatchers("/postsample");
    }
    
}

ここで注意が必要なのは、「ignoringAntMatchers()」で指定するURLはページのURLではなくPostリクエストの送信先のURLであるということです。

そのため、CSRFを有効にするページとそうでないページとでPostリクエストの送信先が一緒になっていると、
両方でログインを求められたりCSRF対策が無効になってしまったりします。

まぁ適当にコピペしているのでもなければ、通常そんなことは無いだろうとは思いますがorz

X-XSRF-TOKENについて

CSRF対策用のトークンなどは、Spring boot側でCSRF対策が有効・無効であるかにかかわらず、常に含まれるようです。

f:id:mslGt:20170804005758j:plain

f:id:mslGt:20170804005810j:plain

ただし、トークンの値はログインのタイミングで更新されるため、

  1. ログイン前にCSRF対策を無効にしたPostリクエストを送信する
  2. ログインして、CSRF対策を有効にしたPostリクエストを送信する
  3. ログイン状態のままCSRF対策を無効にしたPostリクエストを送信する

とすると、2と3で同じトークンが渡され、1とは異なる値になっています。

IDの固定化攻撃の対策も自動で行ってくれる、ということですね。すごい!

Cross-site script inclusion (XSSI)

JSONから重要なデータを読み取られる脆弱性、ということですが、
JSONとしてサーバー側から受け取った値がそのままJavascriptとして実行できる場合にのみ発生するようで、
XSSなどと比較すると常に気をつけなければいけない、という訳でもないのかしら。。。?
(すみません。イマイチ内容が理解できていません)

とりあえず、このXSSIを防ぐ方法としてサーバー側で冒頭に「)]}」や「\n(改行コード)」をJSONデータのプレフィックスとして付与するというものがあり、
AngularのHttpClientではそれらのプレフィックスをJSONの解析前に削除する、というのが本項目の内容です。

おわりに

一通りAngularのSecurityのページを眺めてみました。

軽く触っただけのところなど、気になる部分もありますが、
次からはSpring Security側の設定なども含めて、実際に何かWebアプリでも作りつつ試していくことにしたいと思います。

ブログはせっかくここに書き溜めているわけですし(なお質は問わないものとする)、
PCやスマホからメモを残したりスケジュールを追加したりできるようなものを作ってみようかな?
(できるとは言っていない)

参照

CSRF

XSSI