個人開発でも気軽に使える Copy Protection のサービスをつくりました

この記事は個人開発 Advent Calendar 2020 6日目の記事です。

昨日は @yakipudding さんによる「Reactで作成したポートフォリオサイトをNextに移行した」でした。
改良後のデザインがおっしゃられるとおりとてもスッキリしていて、センスの良さが本当に羨ましかったです。

# はじめに
作った理由は[こちら](https://qiita.com/UedaTakeyuki/items/a2611c27fc89e698be12)に書いたとおりです

３ヶ月ぐらいでできるかと見積もっていたのですが実際はリリースまで６ヶ月もかかってしまい、自分の effort estimation の精度に自信をなくして落ち込んだりもしたのですが、単に私の productivity が普通のエンジニアの半分ぐらいしかなかっただけなのかもしれない[^1]と気をとりなおして今は元気な私はソフトウェア工学屋崩れ[^2]の野良犬です
（Ｕ＾ω＾）

[^2]: 無駄に工学博士持ってます。せっかく博士なんだから、何時の日か自分の戦隊から「博士を守るんだ！」とかやってもらうのが幼少の折より今に至る夢です。戦隊コスとかの人、本物の工学博士を守ってみませんか？ちなみに「博士、お薬の時間ですよ」とかは経験済です

[^1]: もともと RPi だけの、それも SD CARD と Board の ID だけのつもりだったのに、つい NIC を追加したら Mac や Linux 一般にも欲がでて、という途中からの仕様追加を個人開発なのにやりまくったのも悪かったかもしれません

関係ないのですが [Software Engineering at Google](https://learning.oreilly.com/library/view/software-engineering-at/9781492082781/) 読んでて、エンピリカルなソフトウェア工学屋さんの言ういわゆる effort の事を一貫して endeavor って呼んでるのが珍しい言い方[^3]だなとおもいました

[^3]: タイトルに反してそういう人達へのネガティブな感情が前提にあるのかと読んでて勘ぐりました

[こちら](https://qiita.com/UedaTakeyuki/items/a2611c27fc89e698be12)では RPi の話しか書かなかったのですが、RPi[^4] だけでなく Linux でも Mac でも使える汎用[^5]のコピープロテクションですので、皆様も[こちら](https://qiita.com/UedaTakeyuki/items/a2611c27fc89e698be12)に書いたみたいな目にあったりされましたら（されないように）使っていただければと思いまして、老爺心ながら使い方をご紹介させていただきます次第です

[^4]: Raspberry Pi 以外の各種 IoT ボードも Linux ベースであれば IP address や MAC IDに束縛することで利用可能です。ボード固有のIDのへの束縛も対応していきたく、リファレンスボードの [donation](https://github.com/UedaTakeyuki/sansi_examples#for) を募集してます

[^5]: Windows は持ってないので、開発に使える PC の [donation を募集](https://github.com/UedaTakeyuki/sansi_examples#not-for)しています

# サービスの紹介

[Koshitno](https://koshinto.uedasoft.com/docs/) は[Sansi](https://github.com/UedaTakeyuki/sansi_examples) ライブラリと共にアプリケーションのコピープロテクションを提供するクライアント - サーバ型の **No license file** な application anti-piracy サービスです

コピープロテクションって一般にライセンス定義ファイルとかライセンスキーとかを使ってアプリケーションを unauthorized なコピーから保護するものなのですが、ストレージがむき出しな RPi だとそれが弱点になると考え、それらを使わないで実現するためにクライアント-サーバ型で実装しました

クライアント-サーバ型であることで、ネットワークに接続していないスタンドアロンなアプリでは利用できないというネガティブな副作用があるのですが、逆に、扱いが煩わしく失敗すると事故の原因になりかねないライセンスファイルをつかわないですむので**お気軽お手軽**というポジティブな副作用も生じております。世の中捨てる神あれば拾う神あり、人間万事塞翁が馬ということなのでございましょう

## koshinto と sansi のコピープロテクションの仕組み
[こちら](https://github.com/UedaTakeyuki/sansi_examples/blob/master/README.md)に書いたとおりなのですが、sansi ライブラリはユーザーがダウンロードする時からその内部にアプリケーションの束縛条件を一意に表す ID （以下、Bind_id と呼びます）をバイナリで埋め込んであります

sansi ライブラリの提供する confirm() 関数は、呼ばれると各種の環境情報（デバイスのシリアルナンバー、IP アドレス、Mac アドレス等）を収集して、Bind_id と一緒に Koshinto に送信します

koshinto サーバは sansi から送信された情報と、内部に保存するアプリケーションの束縛条件をチェックして、OK/NG の返答をセキュアに返します

koshinto からの OK/NG の応答を confirm() は戻り値でアプリケーションにします

以上、アプリケーションは起動時に confirm() を呼んで、戻り値が NG だったら exit するように一文を入れるだけで copy protection の実装が完了するわけでございます。これは簡単！

![スクリーンショット 2020-11-22 12.35.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/dee455f9-5a6f-21a0-4bfb-5e5a0a159230.png)


この仕組自体の anti-tamper については[こちら](https://qiita.com/UedaTakeyuki/items/a3ffb76f51b8daaf8ccd)に紹介いたしました

## 使用例
### サンプルアプリケーション
10秒間の秒読みを行う、シチュエーションによってはとても practical なアプリケーションです

```main.simple.c:
/*
* 10 second countdown, copy guarded by sansi
* 
* @author Dr. Takeyuki UEDA
* @copyright Copyright© Atelier UEDA 2020 - All rights reserved.
*/

#include <stdio.h>  // for printf
#include <unistd.h> // for seep
void tenseccount();

int main(){
    
  tenseccount();
  return 0;
}

void tenseccount(){
  int i;
  printf("start 10 second countdown\n");
  for (i=10; i>0; i--){
    printf("%d\n",i);
    sleep(1);
  }
  printf("0!\n");
}
```
Practical なので悪意の第三者による意図せぬコピー、著作権侵害をふせぐために sansi を組み込んで保護しましょう

### sansi の組み込み
```main.simple.c:
/*
* 10 second countdown, copy guarded by sansi
* 
* @author Dr. Takeyuki UEDA
* @copyright Copyright© Atelier UEDA 2020 - All rights reserved.
*/

#include "sansi.h"  // for sansi libraries

#include <stdio.h>  // for printf
#include <unistd.h> // for seep
void tenseccount();

int main(){

  if (ok_confirmed == confirm(NULL, NULL, NULL)){
    printf("OK\n");
  } else {
    printf("NG\n");
    return -1;
  }

  tenseccount();
  return 0;
}

void tenseccount(){
  int i;
  printf("start 10 second countdown\n");
  for (i=10; i>0; i--){
    printf("%d\n",i);
    sleep(1);
  }
  printf("0!\n");
}
```
追加したのは以下の２点で
- 8行目: **sansi.h** のインクルード
- 16-21行目: アプリの最初に **confirm()** を呼び、戻り値が **ok_confirmed** でなければ**異常終了**


### サンプルプロジェクトの clone 
完成品は[こちら](https://github.com/UedaTakeyuki/sansi_examples/blob/master/c/main.simple.c)にございますので、git clone して

```bash:
MacBook-Air:tmp takeyuki$ git clone https://github.com/UedaTakeyuki/sansi_examples.git
```

sansi_examples/c フォルダに移動してください

```bash:
MacBook-Air:tmp takeyuki$ cd sansi_examples/c
```

ls してみるといろいろなファイルがあります

```bash:
MacBook-Air:c takeyuki$ ls
README.md	compile.sh	main.c		main.simple.c	sansi.h
```

左からそれぞれ README、 compile スクリプト、別のサンプルの main.c (本稿ではつかいません)、先程紹介した main.simple.c、そして sansi のヘッダーファイルです

ここでは紹介しませんが、C アプリの他に C++, go, python, bash の組込例も用意させていただきました
go は cgo で sansi をリンクする例をご紹介させていただきました。vlang も同様にできるように思っているのですけどまだ試せていません。どなたか pull req いただければ感謝の言葉もございません
python は nuitka でコンパイルして strip すること、bash は [shc](https://qiita.com/UedaTakeyuki/items/26293a28d15af3db77a9) とかでバイナリ化する前提です

### sansi のダウンロード
Koshinto にログインして Home から [Binds]-[All] を選択してください

![スクリーンショット 2020-11-30 18.29.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/7072bbe3-0451-672c-63e1-ec33dde81b81.png)

アカウントを作った直後だと、一つだけですが Bind がすでにあるのでこれを選択して

![スクリーンショット 2020-11-30 18.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/6aaba039-6000-17f3-c74e-f82569d342e4.png)

メニューから Sansi library Download を開き
![スクリーンショット 2020-11-30 18.29.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/57570d26-71dd-2920-c6bc-d69dc5d15523.png)

アプリケーションのターゲットに合わせてライブラリをダウンロードしてください

![スクリーンショット 2020-11-30 18.29.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/33e097cf-a39a-b66c-7bec-d76e5a8d1b28.png)

ダウンロードしたライブラリを先程 git clone したプロジェクトにコピーしてください

```bash:
MacBook-Air:c takeyuki$ cp /Users/takeyuki/Downloads/libsansi_ZbPdGoGyrNkQ_mac_v1.1.o .
MacBook-Air:c takeyuki$ ls
README.md				main.c
compile.sh				main.simple.c
libsansi_ZbPdGoGyrNkQ_mac_v1.1.o	sansi.h
```

### アプリケーションのコンパイル
コンパイルスクリプトの使い方は

```bash
MacBook-Air:c takeyuki$ ./compile.sh -h
Usage: ./compile.sh [-h][-c][-g][-m][-o obj] [source] [libsansi]
  [source]:   compiling source file, default is 'main.sample.c' 
  [libsansi]: path for linking 'libsansi….o', default is found it in cwd automatically 
  [-h]: show this usage and exit
  [-c]: compile for linux by clang
  [-g]: compile for linux by gcc, this is default
  [-m]: compile for mac by clang
  [-o obj] set compiled object file name, default is a.out
MacBook-Air:c takeyuki$ ./compile.sh -m
```

デフォルトで main.sample.c をコンパイルして、デフォルトで a.out をつくります。デフォルトで sansi ライブラリをよしなにさがしてくれるので便利です

#### Mac 用のコンパイルの場合

Mac 用のコンパイルであることを指示する -m を指定します
```bash:
MacBook-Air:c takeyuki$ ./compile.sh -m
source   = main.simple.c
libsansi = libsansi_ZbPdGoGyrNkQ_mac_v1.1.o
compiler = clang
obj      = a.out
compiling…
```

尚、sansi は OpenSSL に依存するのですが、Mac だと OpenSSL がインストールされていないかもしれません。その旨のエラーがでた場合はインストールしてください

#### Linux 用のコンパイルの場合

Linux の場合はなにも指定する必要がありません

```bash:
pi@raspberrypi:~/sansi_examples/c $ ./compile.sh 
source   = main.simple.c
libsansi = libsansi_ZbPdGoGyrNkQ_arm_v1.1.o
compiler = gcc
obj      = a.out
compiling…
```

-c を指定すると gcc の代わりに clang でコンパイルします

```bash:
pi@raspberrypi:~/sansi_examples/c $ ./compile.sh -c
source   = main.simple.c
libsansi = libsansi_ZbPdGoGyrNkQ_arm_v1.1.o
compiler = clang
obj      = a.out
compiling…
```

### 例１. アプリケーションを Mac のシリアル番号に束縛する

Koshinto に戻って Bind のステータスを確認すると **Not Active** になっているはずです

![スクリーンショット 2020-11-30 17.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/4a33f4b2-2c07-af52-0d3b-a7a633671f9c.png)

アプリケーションを Bind する方法は以下の３通りがあります
- 直接、値を入力して Bind
- sansi が取得してきた値を確認して Bind
- sansi が取得してきた値に自動的に Bind 

正常な Bind のステータスは５通りあって、上記の３つの方法によってステータスの遷移がかわります。詳細については
[こちら](#1-bind-%E3%81%AE%EF%BC%95%E7%A8%AE%E9%A1%9E%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92-bind-%E3%81%99%E3%82%8B%EF%BC%93%E9%80%9A%E3%82%8A%E3%81%AE%E6%96%B9%E6%B3%95)を参照ください


#### 1. 事前に取得した key の値に直接束縛する場合
Koshinto に戻って Bind の [Keys] を開きます

![スクリーンショット 2020-11-30 19.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a637a145-7ac9-242c-8db6-e9b929240b71.png)

調べておいた Mac のシリアルナンバーを Platform Serial Number に入力して lock を✓し、右下の UPDATE をクリックします
![スクリーンショット 2020-11-30 19.53.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/d942c6d5-42a5-d15d-c35a-4ed8672145a8.png)

Status を開き、Binding を選択して右下の UPDATE をクリックします
![スクリーンショット 2020-12-02 18.56.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/f268dcf9-68c6-ae58-7355-656f2dfc2ad3.png)



Mac に戻って a.out がブロックされずに実行できているのが確認できます

```bash
MacBook-Air:c takeyuki$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

#### 2. sansi が取得して送信してきた値から選択して束縛する場合

現在の status は Not Active なので
![スクリーンショット 2020-11-30 17.23.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/5595da93-485b-f7e7-807a-42fcd1c87d6f.png)

Bind Waiting に変更して
![スクリーンショット 2020-11-30 17.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/41ebd403-7472-3b8b-e61b-e43fd784542d.png)

右下の UPDATE をクリックします
![スクリーンショット 2020-11-30 17.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/06064d58-9c80-f214-925d-26e1552659f1.png)

Mac に戻り、先程コンパイルした a.out を実行します
結果は NG になりますが、sansi が取得したMac の環境の各種値が Koshinto に送信されて Bind に反映されているはずです

```bash
MacBook-Air:c takeyuki$ ./a.out
NG
```

現在の Bind の値を Koshinto からブラウザに反映させるために、Bind の右下のフローティング・アクション・ボタン[^1]（グルグルみたいな奴）を一度クリックします

[^1]: 昔は qiita でも fontawsome が使えたのでもっと具体的に説明できたんだけどまったく最近の qiita ときたら…

![スクリーンショット 2020-11-30 17.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/8d07da52-eb81-308e-cf5d-74f0c780a487.png)

keys を開くと値が送信されてきています

![スクリーンショット 2020-11-30 17.34.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/98c514c5-dca1-04a6-7e4e-50e0eda609c3.png)

Platform Serial Number の lock を✓して右下の UPDATE をクリックします

![スクリーンショット 2020-11-30 17.35.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/d8a7dffb-21ed-4840-83e1-798dfd45b087.png)

Status は Bind Waiting から Bind Requesting に遷移しています


![スクリーンショット 2020-11-30 17.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/91d4b141-19ea-9bb2-7b07-4fd5ed6186ca.png)

Status を Binding に変更します

![スクリーンショット 2020-11-30 17.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/6bf40911-eb0e-35fd-e5a7-88faf169f296.png)

変更したら右下の UPDATE をクリックして変更を反映させます

![スクリーンショット 2020-11-30 17.35.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a0e61547-269f-6377-de99-6873167a9042.png)

Mac に戻って a.out を実行してみると、今度は正常に起動して１０秒の秒読みが実行されます

```bash
MacBook-Air:c takeyuki$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

#### 3. 何を key にするか決めておいて、sansi が送信してきた値に自動的に束縛する場合

アプリケーションが最初に起動された Mac のシリアルナンバーに自動的に束縛することにします
keys を開いて Platform Serial Number の lock を✓し、右下の UPDATE をクリックして変更を反映させます

![スクリーンショット 2020-11-30 17.22.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/00246de0-d799-1c35-25fe-84a5b73ad3e1.png)

現在の Status は Not Active なので

![スクリーンショット 2020-11-30 17.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/ecdbdbc8-4b7a-36b0-a86a-c0062fdd63b9.png)

Auto Bind Waiting に変更します

![スクリーンショット 2020-11-30 17.23.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/e75b4f9d-1a7e-7851-47c4-d599b8cef575.png)

![スクリーンショット 2020-11-30 17.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/37f24e64-c4dd-ffe8-eb9f-bc6dab4c97d0.png)

Mac に戻って a.out を実行してみると、初回から正常に起動して１０秒の秒読みが実行されます

```bash
MacBook-Air:c takeyuki$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

現在の Bind の値を Koshinto からブラウザに反映させるために、Bind の右下のフローティング・アクション・ボタン（グルグルみたいな奴）を一度クリックします

![スクリーンショット 2020-11-30 17.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/9badad42-0197-d3eb-91e1-8d8cd17b6b5e.png)

keys の値は sansi が収集して送信してきた値に更新されていて、Platform Serial Number も更新されています

![スクリーンショット 2020-11-30 17.25.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/3c1f35e6-490d-50de-e51f-2ace174795a2.png)

Status は Binding に遷移しています

![スクリーンショット 2020-11-30 17.25.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a0501b2e-ff04-d4f4-538f-abbb2d72f9f1.png)


### 例2. アプリケーションを RaspberryPi の SDカードのシリアルIDに束縛する

Koshinto に戻って Bind のステータスを確認すると **Not Active** になっているはずです

![スクリーンショット 2020-11-30 17.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/4a33f4b2-2c07-af52-0d3b-a7a633671f9c.png)

アプリケーションを Bind する方法は以下の３通りがあります
- 直接、値を入力して Bind
- sansi が取得してきた値を確認して Bind
- sansi が取得してきた値に自動的に Bind 

正常な Bind のステータスは５通りあって、上記の３つの方法によってステータスの遷移がかわります。詳細については
[こちら](#1-bind-%E3%81%AE%EF%BC%95%E7%A8%AE%E9%A1%9E%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92-bind-%E3%81%99%E3%82%8B%EF%BC%93%E9%80%9A%E3%82%8A%E3%81%AE%E6%96%B9%E6%B3%95)を参照ください


#### 1. 事前に取得した key の値に直接束縛する場合
Koshinto に戻って Bind の [Keys] を開きます

![スクリーンショット 2020-11-30 19.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a637a145-7ac9-242c-8db6-e9b929240b71.png)

調べておいた SD カードのシリアルナンバーを Platform Serial Number に入力して lock を✓し、右下の UPDATE をクリックします

![スクリーンショット 2020-12-02 18.49.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/44ec28bf-8b05-401a-08fc-3e667b28cfc7.png)

Status を開き、Binding を選択して右下の UPDATE をクリックします
![スクリーンショット 2020-12-02 18.56.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/f268dcf9-68c6-ae58-7355-656f2dfc2ad3.png)

Raspberry Pi に戻って a.out がブロックされずに実行できているのが確認できます

```bash
pi@raspberrypi:~/sansi_examples/c $ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

#### 2. sansi が取得して送信してきた値から選択して束縛する場合

現在の status は Not Active なので
![スクリーンショット 2020-11-30 17.23.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/5595da93-485b-f7e7-807a-42fcd1c87d6f.png)

Bind Waiting に変更して
![スクリーンショット 2020-11-30 17.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/41ebd403-7472-3b8b-e61b-e43fd784542d.png)

右下の UPDATE をクリックします
![スクリーンショット 2020-11-30 17.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/06064d58-9c80-f214-925d-26e1552659f1.png)

Raspberry Pi に戻り、先程コンパイルした a.out を実行します
結果は NG になりますが、sansi が取得したMac の環境の各種値が Koshinto に送信されて Bind に反映されているはずです

```bash
pi@raspberrypi:~/sansi_examples/c $ ./a.out
NG
```

現在の Bind の値を Koshinto からブラウザに反映させるために、Bind の右下のフローティング・アクション・ボタン[^1]（グルグルみたいな奴）を一度クリックします

[^1]: 昔は qiita でも fontawsome が使えたのでもっと具体的に説明できたんだけどまったく最近の qiita ときたら…

![スクリーンショット 2020-11-30 17.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/8d07da52-eb81-308e-cf5d-74f0c780a487.png)

keys を開くと値が送信されてきています

![スクリーンショット 2020-12-02 19.04.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/796127cc-705f-0bad-78a1-846be0ea3ea7.png)

SD Card Serial ID の lock を✓して右下の UPDATE をクリックします

![スクリーンショット 2020-12-02 19.09.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/e6ca0455-5b6b-32f4-8733-3f986f35481f.png)

Status は Bind Waiting から Bind Requesting に遷移しています


![スクリーンショット 2020-11-30 17.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/91d4b141-19ea-9bb2-7b07-4fd5ed6186ca.png)

Status を Binding に変更します

![スクリーンショット 2020-11-30 17.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/6bf40911-eb0e-35fd-e5a7-88faf169f296.png)

変更したら右下の UPDATE をクリックして変更を反映させます

![スクリーンショット 2020-11-30 17.35.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a0e61547-269f-6377-de99-6873167a9042.png)

Raspberry Pi に戻って a.out を実行してみると、今度は正常に起動して１０秒の秒読みが実行されます

```bash
pi@raspberrypi:~/sansi_examples/c $ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

#### 3. 何を key にするか決めておいて、sansi が送信してきた値に自動的に束縛する場合

アプリケーションが最初に起動された Raspberry Pi に装着されている SD カードのシリアルIDに自動的に束縛することにします
keys を開いて Platform Serial Number の lock を✓し、右下の UPDATE をクリックして変更を反映させます

![スクリーンショット 2020-12-02 19.12.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/55adbd53-8d6b-4aea-d022-8e9546cd337a.png)

現在の Status は Not Active なので

![スクリーンショット 2020-11-30 17.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/ecdbdbc8-4b7a-36b0-a86a-c0062fdd63b9.png)

Auto Bind Waiting に変更します

![スクリーンショット 2020-11-30 17.23.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/e75b4f9d-1a7e-7851-47c4-d599b8cef575.png)

![スクリーンショット 2020-11-30 17.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/37f24e64-c4dd-ffe8-eb9f-bc6dab4c97d0.png)

Raspberry Pi に戻って a.out を実行してみると、初回から正常に起動して１０秒の秒読みが実行されます

```bash
MacBook-Air:c takeyuki$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

現在の Bind の値を Koshinto からブラウザに反映させるために、Bind の右下のフローティング・アクション・ボタン（グルグルみたいな奴）を一度クリックします

![スクリーンショット 2020-11-30 17.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/9badad42-0197-d3eb-91e1-8d8cd17b6b5e.png)

keys の値は sansi が収集して送信してきた値に更新されていて、SD Card Serial ID も更新されています

![スクリーンショット 2020-12-02 19.16.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/9f5dae88-fa69-8c7a-e6cc-20bc3d3c42a6.png)

Status は Binding に遷移しています

![スクリーンショット 2020-11-30 17.25.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a0501b2e-ff04-d4f4-538f-abbb2d72f9f1.png)


### 例3. アプリケーションを Linux Server の Global IP address に束縛する

Koshinto に戻って Bind のステータスを確認すると **Not Active** になっているはずです

![スクリーンショット 2020-11-30 17.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/4a33f4b2-2c07-af52-0d3b-a7a633671f9c.png)

アプリケーションを Bind する方法は以下の３通りがあります
- 直接、値を入力して Bind
- sansi が取得してきた値を確認して Bind
- sansi が取得してきた値に自動的に Bind 

正常な Bind のステータスは５通りあって、上記の３つの方法によってステータスの遷移がかわります。詳細については
[こちら](#1-bind-%E3%81%AE%EF%BC%95%E7%A8%AE%E9%A1%9E%E3%81%AE%E7%8A%B6%E6%85%8B%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92-bind-%E3%81%99%E3%82%8B%EF%BC%93%E9%80%9A%E3%82%8A%E3%81%AE%E6%96%B9%E6%B3%95)を参照ください


#### 1. 事前に取得した key の値に直接束縛する場合
Koshinto に戻って Bind の [Keys] を開きます

![スクリーンショット 2020-11-30 19.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a637a145-7ac9-242c-8db6-e9b929240b71.png)

調べておいた Global IP address![スクリーンショット 2020-12-03 22.54.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/8fe8b860-2bc1-85d3-5319-18a9435864df.png)
 を Global IP に入力して lock を✓し、右下の UPDATE をクリックします

![スクリーンショット 2020-12-02 20.37.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/c8de684b-53cd-c7f6-2eb6-32b34de53104.png)


Status を開き、Binding を選択して右下の UPDATE をクリックします
![スクリーンショット 2020-12-02 18.56.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/f268dcf9-68c6-ae58-7355-656f2dfc2ad3.png)

Linux に戻って a.out がブロックされずに実行できているのが確認できます

```bash
ueda@amfortas:~/sansi_examples/c$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

#### 2. sansi が取得して送信してきた値から選択して束縛する場合

現在の status は Not Active なので
![スクリーンショット 2020-11-30 17.23.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/5595da93-485b-f7e7-807a-42fcd1c87d6f.png)

Bind Waiting に変更して
![スクリーンショット 2020-11-30 17.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/41ebd403-7472-3b8b-e61b-e43fd784542d.png)

右下の UPDATE をクリックします
![スクリーンショット 2020-11-30 17.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/06064d58-9c80-f214-925d-26e1552659f1.png)

Linux に戻り、先程コンパイルした a.out を実行します
結果は NG になりますが、sansi が取得したMac の環境の各種値が Koshinto に送信されて Bind に反映されているはずです

```bash
ueda@amfortas:~/sansi_examples/c$ ./a.out
NG
```

現在の Bind の値を Koshinto からブラウザに反映させるために、Bind の右下のフローティング・アクション・ボタン[^1]（グルグルみたいな奴）を一度クリックします

[^1]: 昔は qiita でも fontawsome が使えたのでもっと具体的に説明できたんだけどまったく最近の qiita ときたら…

![スクリーンショット 2020-11-30 17.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/8d07da52-eb81-308e-cf5d-74f0c780a487.png)

keys を開くと値が送信されてきています

![スクリーンショット 2020-12-02 19.04.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/796127cc-705f-0bad-78a1-846be0ea3ea7.png)

Global IP の lock を✓して右下の UPDATE をクリックします

![スクリーンショット 2020-12-03 22.56.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/715021c3-7d4c-9748-8cb8-d14e6e4c528f.png)

Status は Bind Waiting から Bind Requesting に遷移しています


![スクリーンショット 2020-11-30 17.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/91d4b141-19ea-9bb2-7b07-4fd5ed6186ca.png)

Status を Binding に変更します

![スクリーンショット 2020-11-30 17.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/6bf40911-eb0e-35fd-e5a7-88faf169f296.png)

変更したら右下の UPDATE をクリックして変更を反映させます

![スクリーンショット 2020-11-30 17.35.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a0e61547-269f-6377-de99-6873167a9042.png)

Linux に戻って a.out を実行してみると、今度は正常に起動して１０秒の秒読みが実行されます

```bash
ueda@amfortas:~/sansi_examples/c$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

#### 3. 何を key にするか決めておいて、sansi が送信してきた値に自動的に束縛する場合

アプリケーションが最初に起動された Raspberry Pi に装着されている SD カードのシリアルIDに自動的に束縛することにします
keys を開いて Platform Serial Number の lock を✓し、右下の UPDATE をクリックして変更を反映させます

![スクリーンショット 2020-12-03 22.59.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/af33a70d-a988-0442-aa3b-d7348395fec4.png)


現在の Status は Not Active なので

![スクリーンショット 2020-11-30 17.23.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/ecdbdbc8-4b7a-36b0-a86a-c0062fdd63b9.png)

Auto Bind Waiting に変更します

![スクリーンショット 2020-11-30 17.23.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/e75b4f9d-1a7e-7851-47c4-d599b8cef575.png)

![スクリーンショット 2020-11-30 17.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/37f24e64-c4dd-ffe8-eb9f-bc6dab4c97d0.png)

Linux に戻って a.out を実行してみると、初回から正常に起動して１０秒の秒読みが実行されます

```bash
ueda@amfortas:~/sansi_examples/c$ ./a.out
OK
start 10 second countdown
10
9
8
7
6
5
4
3
2
1
0!
```

現在の Bind の値を Koshinto からブラウザに反映させるために、Bind の右下のフローティング・アクション・ボタン（グルグルみたいな奴）を一度クリックします

![スクリーンショット 2020-11-30 17.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/9badad42-0197-d3eb-91e1-8d8cd17b6b5e.png)

keys の値は sansi が収集して送信してきた値に更新されていて、Global IP も更新されています

![スクリーンショット 2020-12-03 23.03.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/debd9ff2-b659-f624-d899-443a62b9af13.png)


Status は Binding に遷移しています

![スクリーンショット 2020-11-30 17.25.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46544/a0501b2e-ff04-d4f4-538f-abbb2d72f9f1.png)

## 詳説
### 1. Bind の５種類の状態と、アプリケーションを Bind する３通りの方法
正常な Bind のステータスは以下の５つのどれかになります。各ステータスで confirm() の通知を受けた際の戻り値と、koshinto 内の bind の key と status の変化を表にまとめました

|status|return|koshinto の bind の key|koshinto 内の bind の status|
|------|------|----|----|
|Not Active|常に ng_comfirmed|変化なし|変化なし|
|Bind Waiting|常に ng_comfirmed|confirm からの値で更新|Bind Requestingに遷移|
|Bind Requesting|常に ng_comfirmed|変化なし|変化なし|
|Auto Bind Waiting|常に ok_comfirmed|confirm からの値で更新|Binding|
|Binding|confirm からの値によって ng_comfirmed またはok_comfirmed|変化なし|変化なし|

Not Active が、Bind が使われていない状態です
Binding が、アプリケーションが束縛されている状態です

アプリケーションを Bind する方法は３種類あって

1. キーの値を設定してロックし、状態を Binding に変更
2. 状態を [Bind Waitingに変更]して sansi からの confirm()を待つ。bind の key が更新され、状態が [Bind Requesting] に変わるので、適切な key を選んでロックし、状態を [Binding]に変更
3. 適切な key を選んでロックしてから状態を [Auto Bind Waitingに変更]して sansi からの confirm()を待つ。key の値が更新されて自動的に [Bind]状態になる

束縛したい key の値（今の場合は Mac のシリアルナンバー）を事前に知っていて（「このマックについて」で確認済で）、その値を使って束縛する場合に 1. の手順になります。調べるのってめんどくさかったり typo があったりすると思うので後述の 2. や 3. の手順をお薦めいたしますが、Bind の状態の推移はシンプルに次のようになります

 [Not Active] -> [Bind]

束縛したい key の値を知らない、もしくは自分で調べるのがめんどくさいので sansi に任せたい場合、**sansi が送ってくる値を確認**して問題がなければその値に束縛する場合が 2. の手順になります。遷移は

 [Not Active] -> [Bind Waiting] -> [Bind Requesting] ->[Bind] 

**確認せずに自動的**にその環境に束縛するのが 3. の手順になります。遷移は

 [Not Active] -> [Auto Bind Waiting] -> [Binding]

# related works
[こちら](https://qiita.com/UedaTakeyuki/items/a2611c27fc89e698be12#related-works)を参照いただければ幸いです

# 名前の由来
Koshinto と Sansi の名前の由来は[こちら](https://koshinto.uedasoft.com/docs/origin/)を参照賜われれば至福の至に存じます次第です

# 結び
長々と書いてしまい本当にどうもすみません、今は謹んで反省しております次第です、無駄に長生きした年寄りの話が無駄に長いのは相応というものでございますれば、エンジニアの情けで許してくだされ／(^o^)＼

# references 
- [Raspberry Pi のアドベント](https://qiita.com/advent-calendar/2020/raspberry-pi)に記事を[書きました](https://qiita.com/UedaTakeyuki/items/a2611c27fc89e698be12)
- [セキュリティのアドベント](https://qiita.com/advent-calendar/2020/security)に Koshinto 自身の anti-tamper について[書きました](https://qiita.com/UedaTakeyuki/items/a3ffb76f51b8daaf8ccd)
- [Koshinto Docs](https://koshinto.uedasoft.com/docs/) Koshinto のドキュメント
- [Koshinto](https://koshinto.uedasoft.com/) Koshinto サービスの入り口
- [Sansi_Example](https://github.com/UedaTakeyuki/sansi_examples) アプリケーション への Sansi の組み込み方の言語毎の解説とサンプル。現在、c, go, python, bash の例を用意しています
- [庚申信仰](https://ja.wikipedia.org/wiki/%E5%BA%9A%E7%94%B3%E4%BF%A1%E4%BB%B0) 蛇足ながら Wikipedia

# 明日は
明日は@azukisiromochiさんによる「アプリ名『焼き鳥』事件 😱😱😱」です！私は前日なのでメンションもらって限定公開の頃から読ませて頂いてたのですが、正直、ものすごくおもしろい、ためになるお話なんですよ！お楽しみに！