【Python】Blockchainの電子署名

電子署名を行うために、ecdsaをインストール
$ pip3 install ecdsa

from ecdsa import SigningKey, BadSignatureError, SECP256k1

secret_key = SigningKey.generate(curve = SECP256k1)
print("秘密鍵:" + secret_key.to_string().hex())
public_key = secret_key.verifying_key
print("公開鍵:" + public_key.to_string().hex())

doc = "これは送信したい文章です。"
signature = secret_key.sign(doc.encode('utf-8'))
print("電子署名" + signature.hex())

try:
	public_key.verify(signature, doc.encode('utf-8'))
	print("文章は改竄されていません。")
except BadSignatureError:
	print("文章が改竄されています")

SECP256k1は楕円曲線
電子署名は元の文章から作成されたか否かの判別を行う

秘密鍵:47c5c280197c691be3f80462b72d60b7b2915753f1a81a6eedbfbb2f01f55cae
公開鍵:02cfbf50fe5873ac6e5352e7524c4934e32f01281fc7d6112fed86cf58e72b09bb302f1f7d10d7c37d13eb7e62fd8bb1950b263c51ac76581f8b0a38d0d8853e
電子署名d17955d7f850edf05dde3e363a23dd0452420ec351dccd203f15479970a011c3dcb60b5629a33a7846727d9041e1b6d7be796b909b8ba803c490ace73a1c18e4
文章は改竄されていません。

Blockchainのトランザクション

transaction1 = {“time”: “”, “sender”: “C”, “receiver”: “D”, “amount”: 1}

トランザクションの作成

import datetime

time_now = datetime.datetime.now(datetime.timezone.utc).isoformat()
transaction1 = {"time": time_now, "sender": "C", "receiver": "D", "amount": 1}

time_now = datetime.datetime.now(datetime.timezone.utc).isoformat()
transaction2 = {"time": time_now, "sender": "D", "receiver": "E", "amount": 3}

transactions = [transaction1, transaction2]
print(transactions)

$ python3 transaction.py
[{‘time’: ‘2023-09-23T06:31:46.973357+00:00’, ‘sender’: ‘C’, ‘receiver’: ‘D’, ‘amount’: 1}, {‘time’: ‘2023-09-23T06:31:46.973375+00:00’, ‘sender’: ‘D’, ‘receiver’: ‘E’, ‘amount’: 3}]

ubuntuにflutterをインストールでデプロイ

Flutter公式のインストールページを参考に、snapでflutterをインストールします。
https://docs.flutter.dev/get-started/install/linux

$ sudo snap install flutter –classic
$ flutter sdk-path

続いてflutterで開発したgithubのソースコードをリポジトリからcloneします。
$ git clone https://github.com/hpscript/flutter_test.git
$ cd flutter_test

$ flutter build web
あれ、githubのものをサーバ上でbuildするのではないの?
それとも、開発環境でbuildしたものをpushしてデプロイするのか?

.gitignoreでbuildをコメントアウトしてpush, pullしてサーバに置くとbuild/webをドキュメントルートとして表示できるようになる。

**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
#/build/

なるほど、flutterのデプロイについては何となく理解した。
dartで書いて、buildすれば良いのね。 良く出来ているわ。

nginxのドキュメントルート

nginxのドキュメントルート
/usr/share/nginx/html

almalinux8.8を使って、var/www/htmlがなかったので焦りました…
$ ls
adm crash empty games kerberos local log nis preserve spool yp
cache db ftp gopher lib lock mail opt run tmp

【Flutter】firebaseへのデプロイ

### build
firebaseへデプロイする前に、ファイルをcompileします
$ flutter build web

Fireforceのhosting機能を有効化
プロジェクトのcurrent directoryで
$ sudo npm install -g firebase-tools –force
$ firebase login
プロジェクトの初期化
$ firebase init
=> publicのdirectoryを ./build/web/ で設定する

firebase
$ firebase deploy

webアプリをbuildする
$ flutter build web
$ firebase deploy

firebase hostingを無効化する
$ firebase hosting:disable

OKKKKKKKKKKKKKKKK

【flutter】session_storageでセッション管理

Flutterでsession_storageのパッケージを利用します。
https://pub.dev/packages/session_storage

pubspec.yaml

dependencies:
  session_storage:
  form_field_validator:
  flutter:
    sdk: flutter

main.dart

import 'package:session_storage/session_storage.dart';
// 省略
            onTap: (int value) {
              if (value == 1)
                SessionStorage()..addAll({'language': 'english'});
                Navigator.push(
                  context,
                  MaterialPageRoute(builder:
                      (context)=> SecondScreen()),
                );
            }
// 省略

        body: Center(
          child: Container (
            child: Text(
                'Here: ${session['language']}',
                style: const TextStyle(fontSize:32.0)),
          ),
        ),

セッションとDBが使えるとかなり幅が広がる

【flutter】firestoreでフィールドの値があるかDartで判定

firestoreにフィールドの値が挿入されているか確認し、値の有無によってflutter側でリダイレクト処理を行う
=> 単純にif nullで処理できる

    final snapshot = await firestore.collection('mydata').doc('12345678').get();
    final Map<String, dynamic>? mydata = snapshot.data();
    if (mydata?['hoge']  != null) {
      msg = '値があります';
    } else {
      msg = '値がありません';
    }

これにアラートメッセージを追加する

    if (mydata?['hoge']  != null) {
      msg = '値があります';
    } else {
      showDialog(
        context: context,
        builder: (BuildContext context) => AlertDialog(
          title: Text("値がありません"),
          content: Text("値がありません"),
        )
      );

エリアを指定してアラート文を表示が一般的かもしれないが、アラートダイアログなどを一発で実装できるのもFlutterの良いところですね。

【flutter】firestoreから1件取り出す

docでuidを指定した後に、mapで取得する。その際に、Mapではなく、Map?とする。また、mapは mydata[‘name’] とするとエラーになるので、mydata?[‘name’]とする。

    String? msg = '';
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata').doc('12345678').get();
    final Map<String, dynamic>? mydata = snapshot.data();
    msg = mydata?['name'];
    _controller.text = msg!;

firestoreではなく、flutterの中でmap型を指定する場合は以下のように書いてOK

    final Map<String, String> frameworks = {
      'Flutter' : 'Dart',
      'Rails' : 'Ruby',
    };

コレクションを複数指定する場合とは書き方が大分異なる

    var msg = '';
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata').orderBy('name', descending: false).get();
    snapshot.docChanges.forEach((element) {
      final name = element.doc.get('name');
      final mail = element.doc.get('mail');
      final age = element.doc.get('age');
      msg += "${name} (${age}) <${mail}>\n";
    });
    _controller.text = msg;

【flutter】firestoreを更新する方法

uidを指定して、setを実行するとcollection自体の値が全て更新されてしまう。

    var msg = _controller.text;
    final data = {
      'address': msg,
    };
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata').doc('12345678').set(data);

コレクション自体を残す場合はsetではなく、updateを使用する

    var msg = _controller.text;
    final data = {
      'address': msg,
    };
    FirebaseFirestore firestore = FirebaseFirestore.instance;
    final snapshot = await firestore.collection('mydata').doc('12345678').update(data);

【Flutter】別ページへのデータの引き渡し

引数に値を入れる

  static var _prev = 'ページ1';
  
  void buttonPressed() {
    setState(() {
      // Navigator.pushNamed(context, '/complete');
      Navigator.push(context, MaterialPageRoute(builder: (context)=>CompleteScreen(_prev)),);
    });
  }

複数画面の入力フォームなどはどのような設計にするかは要検討か