投稿者「wpepea」のアーカイブ

ESP8266用(BearSSL_CertStore.ino)のSSL接続用ファイル更新

コマンドプロンプトにて

足りない

Traceback (most recent call last):
  File "C:\Users\kitam\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\examples\BearSSL_CertStore\certs-from-mozilla.py", line 28, in <module>
    raise Exception("You need the program 'ar' from xtensa-lx106-elf found here: (esp8266-arduino-core)/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/xtensa-lx106-elf/bin/ar")
Exception: You need the program 'ar' from xtensa-lx106-elf found here: (esp8266-arduino-core)/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/xtensa-lx106-elf/bin/ar

メッセージとパスがだいぶ違うけど下にいた。microsoftストアから入れると触れないところにあるかも。

C:\Users\kitam\AppData\Local\Arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\3.1.0-gcc10.3-e5f9fec\xtensa-lx106-elf\bin

公式のexampleフォルダの中で作業したくないので、exampleのBearSSL_CertStore.inoをとりあえずデスクトップに保存。 とりいそぎここまで

ArduinoIDEのRasberry Pi PicoボードマネージャーとWindowsの組み合わせでフォルダを握りっぱなしになっている

環境

  • Windows 11 Home 22H2 22621.3155
  • Arduino IDE 2.3.2(おそらく2.2.2-nightly-20230909が自動アップデートかかったもの)
  • python3.10(PCのやつでなくボードマネージャー個別のpythonが指定されていた)
  • Rasberry Pi Pico/PR2040 3.7.2(ボードマネージャー) <- 調査完了してないがこいつが原因
  • python3.7.2(PCのやつでなくボードマネージャー個別のpython)

状況

調査の過程でボードマネージャーからRasberry Pi Pico/PR2040をアンインストール(remove)と再インストールした時点で再現しなくなってしまったので再現待ち。多分根本解決していない。

事象

ArduinoIDEでスケッチを開いた後にスケッチの入っているフォルダを移動させようとすると「別のプログラムがこのフォルダーまたはファイルを開いているので操作を完了できません」というメッセージが表示される。リソースモニターから見るとpython3が握っていることになっている。

なお、リソースモニターはwindowsの下タブにある検索に perfmon.exe /res と入力すると起動できる。(初回はなにか選択画面出たかも)CPUタブの下にある関連付けされたハンドルにフォルダの古パスを入力すると握っているプロセス名とPIDがわかる。

取り急ぎリソースモニターの下の関連付けられたハンドルに出てきたプロセスを右クリックで終了させると解放されるけど気持ち悪い。

調査(中)

プロセス確認

MSのプロセスツリーを確認できるツールをダウンロード&解凍。dosからたたいてプロセス確認。

IDE起動中にPID9552でpythonが起動していたが、閉じたところ

単独でプロセスがのこってしまっている。

ネットをパッと見る限り情報なさそう。

ちなみに以前使っていたArduinoIDE1.8.19を起動したところ1.8.19では発生せず。2になる時に根本的に変わっているので2系の問題っぽい。

上のプロセスツリーを見る限りArduino IDEが動かしているarduino-cliが動かしているpython3がフォルダをにぎりっぱになっているのだろう。

とりあえずタスクマネージャーから引っ張ってきた怪しげなところの起動時引数が下。

名前 PID 状態 ユーザー名 CPU メモリ (アクティブなプライベート ワーキング セット) コマンド ライン アーキテクチャ 説明
arduino-cli.exe 10208 実行中 kitam 00 88,832 K "C:\Users\kitam\AppData\Local\Programs\Arduino IDE\resources\app\lib\backend\resources\arduino-cli.exe" daemon --port 0 --config-file c:\Users\kitam\.arduinoIDE\arduino-cli.yaml -v x64 arduino-cli.exe
名前 PID 状態 ユーザー名 CPU メモリ (アクティブなプライベート ワーキング セット) コマンド ライン アーキテクチャ 説明
python3.exe 15928 実行中 kitam 00 4,112 K C:\Users\kitam\AppData\Local\Arduino15\packages\rp2040\tools\pqt-python3\1.0.1-base-3a57aed/python3 -I C:\Users\kitam\AppData\Local\Arduino15\packages\rp2040\hardware\rp2040\3.7.2/tools/pluggable_discovery.py x86 Python

rp2040といっているのでraspi pico用のやつが悪さしているっぽい。

試しにボードマネージャーからRasberry Pi Pico/PR2040をアンインストール(remove)するとpythonのプ℟セス立ち上がらなくなり閉じたあともきちんと解放されるようになった。

ちなみに以下のjsonで指定しているもの。

原因ソース

多分こちら。スレッドのグローバル変数を外部から操作する思想みたいだが、操作元がいない模様。

どうしよう。

と、思っていたところ再インストールした時点で予想外に再現しなくなったので再現待ち。多分解決しておらず、なにかトリガーになるアクションを踏んでいない。

BrokenPipeError: [Errno 32] Broken pipe調査

事象

esp8266 -> nginx(proxy) -> python(HTTPServer)という構成でサーバへespからサーバーへリクエストを投げたところ、かなりの確率で以下のログがpythonで吐かれていた。

Exception occurred during processing of request from ('127.0.0.1', 48024)
Traceback (most recent call last):
  File "/usr/lib/python3.10/socketserver.py", line 316, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/lib/python3.10/socketserver.py", line 347, in process_request
    self.finish_request(request, client_address)
  File "/usr/lib/python3.10/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python3.10/socketserver.py", line 747, in __init__
    self.handle()
  File "/usr/lib/python3.10/http/server.py", line 433, in handle
    self.handle_one_request()
  File "/usr/lib/python3.10/http/server.py", line 421, in handle_one_request
    method()
  File "/home/yoshitake/api/mail_api.py", line 26, in do_GET
    self.wfile.write(response_content)
  File "/usr/lib/python3.10/socketserver.py", line 826, in write
    self._sock.sendall(b)
BrokenPipeError: [Errno 32] Broken pipe

直接のメッセージは、pythonがリクエスト元に書きこもうとしたら相手がすでに受信待ち状態を終了しているような場合に起きるやつ。esp側では接続したもののヘッダーも取得せずにすぐに終了している。

ちなみにnginxのaccess.logには以下のようにステータス499と(pythonのHTTPServer他で使われている非標準の)クライアントが先に閉じたよというのが残っている。

150.9.94.220 - - [26/Feb/2024:11:31:56 +0900] "GET /api/reserve_count HTTP/1.0" 499 0 "-" "ESP8266"

直接の原因箇所

リクエストを送るesp側でデータの受信待ちをしなくてすぐに閉じているのが直接の原因

delay(1000);とかを入れたらとりあえず動く。

とはいえ、リクエストを送ったのちにデータ受信後の終了信号的なものをみたらまたはタイムアウトでクローズの方がよさそう。

また、同じ接続方式でself-signed.badssl.comにリクエストを送るとレスポンスがきちんと取得できているのでサーバサイドにも何か改善点がありそう。

根本解決

クライアントサイド(ESP8266)

取り急ぎavailable()では接続できたかしか確認していない。 WiFiServerSecureBearSSL.cpp(サーバの方)を間違えてみていた。

改めてWiFiClientSecureBearSSL.cpp確認。

字面で見る限りなんか入ってたら0以外が入って、なにも入っていないとサーバ側が準備中でも一番下に入って0がくるっぽい。だいぶ中の方に書いてあるので内部データを見ると色々多変そうなので最初のデータ来るかタイムアウトまでの待ち処理を入れるのがよさそう。断続的にデータがくるならちゃんと終端処理を見た方がよいかも。

本体から、書き出しメソッド呼び出し。

サーバサイド(nginx+pythonのHTTPServer)

こちらは単純にレスポンスが早く返りだすかどうかで違いが出ていたっぽい。レスポンスが早いという理由だった場合はクライアント側の処理で解決すべき話なので深く追わない。

ESP8266用(BearSSL_Validation.ino)のSSL接続用ファイル更新

こちらのBearSSL_Validation.ino事前準備の手順。試している環境はWindows11。

前提

BearSSL_Validation.inoと同じディレクトリにあるcerts.hだが、サーバ側の証明書が更新されているとつながらなかったりする。(レポジトリ側の更新タイミング次第ではつながったりつながらなかったりだと思う)

certs.hを見ると下のように書いてあり

// this file is autogenerated - any modification will be overwritten
// unused symbols will not be linked in the final binary
// generated on 2023-03-20 23:02:42
// by ['../../../../tools/cert.py', '-s', 'www.example.com', '-n', 'SSL']

して更新するらしい。他のドメイン用に作る場合もおそらくcert.pyをたたけばよいと思う。

なお、cert.pyのファイル先頭コメント

#!/usr/bin/env python3

# Script to download/update certificates and public keys
# and generate compilable source files for c++/Arduino.
# released to public domain

Windowsのはまりポイント

WindowsでMS Storeからインストールするとツールは見れない場所にありそう。(MS Storeから入れたソフト類のディレクトリは見れない模様)インストーラー直ダウンロードしたIDE場合多分下みたいな配置。

C:\Users\hoge\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\examples\BearSSL_Validation

だと下にある

C:\Users\hoge\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\tools

MS Storeからインストールして見れない人は、レポジトリのソース一式ダウンロードしたら多分中に入っているcert.pyを使える。

環境構築

cert.pyはpython3なので必要ならインストール。

ライブラリインストール

ないと下みたいなメッセージ

python  '../../../../tools/cert.py' '-s' 'www.example.com' '-n' 'SSL'                            
Traceback (most recent call last):
  File "C:\Users\kitam\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\tools\cert.py", line 15, in <module>
    from cryptography import x509
ModuleNotFoundError: No module named 'cryptography'

もしかしたら

もいるかも。

import re
import ssl
import sys
import socket
import argparse
import datetime

あたりは元々使えると思うけど必要ならそいつらも

証明書生成実行

パスにユーザ名入っているので適宜書き換え。

出力ファイル名(test.h)も適宜書き換え

結果

PS C:\Users\kitam\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\libraries\ESP8266WiFi\examples\BearSSL_Validation> python  '../../../../tools/cert.py' '-s' 'www.example.com' '-n' 'SSL' > test.h
C:\Users\kitam\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\tools\cert.py:44: CryptographyDeprecationWarning: Properties that return a naïve datetime object have been deprecated. Please switch to not_valid_before_utc.
  print('// not valid before:', xcert.not_valid_before)
C:\Users\kitam\Documents\ArduinoData\packages\esp8266\hardware\esp8266\3.1.2\tools\cert.py:45: CryptographyDeprecationWarning: Properties that return a naïve datetime object have been deprecated. Please switch to not_valid_after_utc.
  print('// not valid after: ', xcert.not_valid_after)

なんか余計な警告出ているけどchatgpt先生によると以下らしいのでとりあえず無視

この警告は、Cryptography ライブラリが提供する一部の機能において、適切なタイムゾーン情報が欠如している(naïveな)datetimeオブジェクトを返すプロパティが非推奨であることを示しています。代わりに、not_valid_before_utcというプロパティを使用することが推奨されています。

ino修正

修正目的

ExampleのBearSSL_Validation.inoを任意フォルダ(今回はデスクトップ)に保存。

その後、cert.hの中身を先ほど出力したtest.hに変更

そのまま実行すると

C:\Users\kitam\Desktop\BearSSL_Validation\BearSSL_Validation.ino: In function 'void fetchCertAuthority()':
C:\Users\kitam\Desktop\BearSSL_Validation\BearSSL_Validation.ino:15:14: error: 'cert_DigiCert_TLS_RSA_SHA256_2020_CA1' was not declared in this scope; did you mean 'cert_DigiCert_Global_G2_TLS_RSA_SHA256_2020_CA1'?
   15 | #define CERT cert_DigiCert_TLS_RSA_SHA256_2020_CA1
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\Users\kitam\Desktop\BearSSL_Validation\BearSSL_Validation.ino:15:14: note: in definition of macro 'CERT'
   15 | #define CERT cert_DigiCert_TLS_RSA_SHA256_2020_CA1
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

exit status 1

Compilation error: 'cert_DigiCert_TLS_RSA_SHA256_2020_CA1' was not declared in this scope; did you mean 'cert_DigiCert_Global_G2_TLS_RSA_SHA256_2020_CA1'?

出力されたtest.hにあるcert_DigiCert_Global_G2_TLS_RSA_SHA256_2020_CA1が元ヘッダーファイルにあったcert_DigiCert_TLS_RSA_SHA256_2020_CA1から変わっている。ちなみに、cert_DigiCert_Global_Root_G2とcert_DigiCert_Global_Root_CAも変わっている。

証明書のCNからcert.pyで自動命名しているのでしょうがない。

長期運用するならcert.pyをいじるか出てきたヘッダーの命名を書き換えて固定にした方が良いかも。深く考えないで取り急ぎinoの方を修正する。(15行目)

動作確認は元のページ

ESPのWiFiClientSecureでサーバから情報をもらう時サーバでContentsLength指定していないと面倒

現象

ESP8266のWiFiClientSecureでサーバからデータを取得しようとした。本来レスポンスの本体(ペイロード本文)は”[0]“を期待していたが以下の下3行のようにレスポンスが期待していたものと違う形になっていた。

Connecting to https://hoge.co.jp/api/fuga
Connected to server
Server: nginx
Date: Wed, 21 Feb 2024 05:21:47 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: close

3
[0]
0

理由

これはTransfer-Encoding: chunkedになっていてペイロード本文

データ1のバイト数\r\nデータ1\r\n0\r\n

というフォーマットになっているため。長いもの送る場合は

データ1のバイト数\r\nデータ1\r\nデータ2のバイト数\r\nデータ2\r\n…データxのバイト数\r\nデータx\r\n…0\r\n

となる。なおデータのバイト数は16 進数表記。

対処

その1

対処としてそういうものとして読み込んでもよいけど、マルチバイトの場合データ1,2の間でぶった切られるのでつなげるのとか面倒。

その2

可能ならサーバ側で送る際にTransfer-Encoding: chunkedじゃなくしたい。

今回はサーバ側はpythonのBaseHTTPRequestHandlerを使っているがレスポンスにContent-Lengthをつけてやれば自動でTransfer-Encoding: chunkedじゃなくなった。「とりあえず、Content-Lengthついてないからchunkedでおくとっくわ」という仕様だったっぽい。(明示的にヘッダー付けた場合に消えるかは未確認)

http1.1の仕様的にはTransfer-Encoding: chunkedの時にはContent-Length不要らしい。

ATTinyのArduinoIDE用パッケージダウンロード先の暫定対処

いつの日からかArduinoIDEで追加ボードマネージャーURLに入れていたAttiny用(プロジェクトの正式名称ATTinyCore?megatinycore?)のjsonがダウンロード先の証明書が切れてつながらなくなっていた。

Some indexes could not be updated. Get "https://drazzy.com/package_drazzy.com_index.json": tls: failed to verify certificate: x509: certificate has expired or is not yet valid: : http://drazzy.com/package_drazzy.com_index.json

adafruitのgithubに以下の暫定対処先のURLダウンロード先がのっていたのでそちらに修正

https://web.archive.org/web/20230504110614/http://drazzy.com/package_drazzy.com_index.json

ArduinoIDEのprefarences->settingタブ->additional board manager urls

とりあえず暫定対処っぽいこと書いてあるけど、数か月前にfixされてそのままみたいなのでしばらくそのままかも

ESP8266のWiFiClientSecure系でcertを扱う時のメモ

今、調べながら試しているけどchatgptに存在しないメソッド言われたりと騙されるっぽいのでメモを残す。

環境

  • Windows11
  • Arfuino IDE 2.3.1
  • esp8266 by ESP8266 Community 3.1.2(レポジトリ)

動きそうなやつ(これから確認、動いたら記事修正する)

WiFiClientSecureBearSSL#setInsecure

基本こちらのまんまで動いた。(リンク先はESP8266でなくESP32なので他を参考にするときはクラス仕様違うので注意)

最初は戻り値にバイト数とか入ってたけどサーバ側でcontents-length指定していないのが原因だった。

BearSSL_Validation.ino

Example->Esp8266Wifiの中にいるサンプル。

単独のCAをツールでヘッダーファイルに変えて読み込むやつだと思う。

includeで気になった奴

#include <StackThunk.h>というのがある。(実装のcpp

StackThunk.c - Allow use second stack for BearSSL calls


  BearSSL uses a significant amount of stack space, much larger than
  the default Arduino core stack. These routines handle swapping
  between a secondary, user-allocated stack on the heap and the real
  stack.

BearSSLはスタックすごい使うからうんぬんと。通常のスタックだと足りないから、ヒープを使ってごにょごにょしてくれるらしい。

サンプルソースだと割り当て関連の機能は使っておらず使用量確認のみに見えるけど中で読んでいるかも。一見、足りてそうに見えるときも内部でこいつが使い切ってるとかはあるかもしれないので心に留めておく。

事前準備

cert.pyを使用して証明書のデータを更新。(長くなったのでこちら

フィンガープリントだけで接続

フィンガープリント設定すればとりあえずつながる。

何もないよりましだといっている

The SHA-1 fingerprint of an X.509 certificate can be used to validate it
instead of the while certificate.  This is not nearly as secure as real
X.509 validation, but is better than nothing.  

自己署名証明書で接続

allowSelfSignedCertすればOKとのこと。

こいつは自己署名は誰でも作れるから注意を(略

It is also possible to accept *any* self-signed certificate.  This is
absolutely insecure as anyone can make a self-signed certificate.

ハードコード公開鍵で接続

公開鍵をハードコードしておいてそいつを使って(通常のSSLは認証プロセスを飛ばして)通信できる。一般公開しないサービスならこれでもよさそうな気がする。

The server certificate can be completely ignored and its public key
hardcoded in your application. This should be secure as the public key
needs to be paired with the private key of the site, which is obviously
private and not shared.  A MITM without the private key would not be
able to establish communications.

certをハードコード方式(多分一番固い)

certをハードコードして検証する方式。

有効期限チェックはするけれどもCRLはサポートしていないらしい。発行された証明書が有効期限内に無効化されていてもチェックされない。自己署名証明書をルートにしたチェーンも作れるらしい。

A specific certification authority can be passed in and used to validate
a chain of certificates from a given server.  These will be validated
using BearSSL's rules, which do NOT include certificate revocation lists.
A specific server's certificate, or your own self-signed root certificate
can also be used.  ESP8266 time needs to be valid for checks to pass as
BearSSL does verify the notValidBefore/After fields.

上のようにcertをルート証明書にしても動くはずだがレスポンスとりそびれるときがあるのに気づいた。ルートじゃなくてサーバのcertを使っているときも取りそびれ発生しているかもしれない。原因調査未。とり急ぎ調査はおいておいて他の方式の確認進める。と、思ったら方式別でも発生している。

暗号化方式の選択

早さ優先したいときとか

client.setInsecure();

ノーチェック

client.setCiphersLessSecure();

以下のやつら指定(と思う)

// For apps which want to use less secure but faster ciphers, only
  static const uint16_t faster_suites_P[] PROGMEM = {
    BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
    BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
    BR_TLS_RSA_WITH_AES_256_CBC_SHA,
    BR_TLS_RSA_WITH_AES_128_CBC_SHA };
  • BR_TLS_RSA_WITH_AES_256_CBC_SHA256: RSA鍵交換、AES-256-CBC暗号、SHA-256ハッシュ
  • BR_TLS_RSA_WITH_AES_128_CBC_SHA256: RSA鍵交換、AES-128-CBC暗号、SHA-256ハッシュ
  • BR_TLS_RSA_WITH_AES_256_CBC_SHA: RSA鍵交換、AES-256-CBC暗号、SHA-1ハッシュ
  • BR_TLS_RSA_WITH_AES_128_CBC_SHA: RSA鍵交換、AES-128-CBC暗号、SHA-1ハッシュ
自分で指定

使えるリストはおそらくこちら。(さらに制限かかっているかもしれないが細かくは追っていない)

ちなみにサンプルソースのwww.example.comはsha1のBR_TLS_RSA_WITH_AES_256_CBC_SHAとBR_TLS_RSA_WITH_AES_128_CBC_SHAは通じたがsha256では通じなかったので上の指定だと接続エラーになった。

つなげるサーバの証明書を取得

こちらを参照

変数名サンプルソースと違うので適宜修正

BearSSL_CertStore.ino

モジラから読み込んだルートcaを複数ストアして使えるやつっぽい。容量気にしない状況ならこいつが使いやすそう。

Chatgptに言われたけどなさそうな奴

無いっぽい奴1

とchatgptにいわれた。が、

C:\Users\kitam\Desktop\https\https.ino: In function 'void setup()':
https:32:10: error: 'class BearSSL::WiFiClientSecure' has no member named 'setCACertBundle'
   32 |   client.setCACertBundle(x509_crt_bundle);
      |          ^~~~~~~~~~~~~~~
exit status 1
'class BearSSL::WiFiClientSecure' has no member named 'setCACertBundle'

ないよと。ソース見ると確かにいない。なお、ESP32ならこれで動く模様。(参考

無いっぽい奴2

といわれたが、同じように

C:\Users\kitam\Desktop\https\https.ino: In function 'void setup()':
C:\Users\kitam\Desktop\https\https.ino:32:9: error: 'class BearSSL::WiFiClientSecure' has no member named 'addServerKey'
   32 |  client.addServerKey(x509_crt_bundle);
      |         ^~~~~~~~~~~~

exit status 1

Compilation error: 'class BearSSL::WiFiClientSecure' has no member named 'addServerKey'

addServerKeyはぱっとみESP32のライブラリにもなさそうなのでchatgptがどこから拾ってきたかよくわからない。

nginxでpythonを動かす

最終的にやりたいこと

店の予約メールが入ったときにすぐわかるように家でパトランプ的なものを光らせたい。

  1. メールサーバに予約っぽいメールが来たら特定フォルダに振り分けておいて
  2. 未読メールがあるかどうか返すAPIをメールサーバに建てておいて
  3. 家のパトランプてきな端末から定期的にサーバをチェックしにいく

家の端末にサーバ側から投げるのは家のファイヤウォールあけるか端末側からつなげっぱにして切れたら再接続とか面倒なことになりそうなので端末側から定期的に見に行く。セキュリティ的にも件数返すだけAPIならあんま頑張んないでもよさげなので。

今回やる範囲

2のAPIを立てるとこ。nginxは未インストールの状態から。pythonはhttp.serverあたりを使ってnginxからproxyで飛ばす予定。あとは実作業しながら書いていく。

開始前の状況

postfix+dovecotでMaildir形式でメールサーバを構築済み。なお、”Ubuntu 22.04.3 LTS”

また、LetsEncriptでtls通信をさせているため証明書も入手済み。ただ、80番ポートが空いている前提のstandaloneモードで証明書の更新をしているためwebroot方式?だかに直さないといけないはず。

メールサーバに予約っぽいメールが来たときはsieveで規定フォルダに振り分けている。設定ファイルはしたので、題名に”予約確定通知”か”予約が確定”とあったら”INBOX.ジム.予約”フォルダに振り分けるというもの。(サンダーバードだと”「受信トレイ」の下の「ジム」の下の「予約」”)

作業開始

nginxインストール&設定

して、とりあえず443ポートをあける。(letsencript使うのに80番も開ける必要があるはずなので空いてなければそちらも)

既に作成済みの証明書を見る形でhttpsを有効にする。ついでにhttpからhttpsへのリダイレクトもかけておく。あと、nginxのバージョンも一応隠す。

で新規ファイルを作り下を追加

でnginx再起動

これでとりあえずブラウザからサーバにサクセスするとhttpsに転送されてnginxにもとから入っているwelcome画面が表示されるはず。

pythonを使えるようにする

nginx側のproxy設定

ssl.conf(と深く考えずに名前を付けたので)に直接かくものじゃないのでインクルードして/etc/nginx/conf.d/mail_api.txt に設定を書く。mail_api.confと拡張子をconfにすると/etc/nginx/nginx.confからのinclude設定と重なり多分うまく動かない。

でserver(443の方)の末尾にインクルード設定を追加

そしてmail_api.txtを作成

にて

これでsudo systemctl restart nginx したら8000番ポートで起動している奴があればそちらにリクエストをすべて飛ばすはず(location / で ルートディレクトリ以下全部)。8000番起動していなくてもとりあえずnginxを先に起動できると思う。

python側のリクエスト受信

http.serverにてnginxのproxyで指定した8000番ポートで待ち受け機能を作る。

(本来ローカルで完結するのでファイヤウォールの8000番は開かなくてよいけどVSCodeでやるとちょいちょいつなげに行こうという処理が走って面倒だった)

取り急ぎmailサーバの任意の場所に以下のmail_api.pyを作ってpython3 mail_api.pyで起動

ローカルのPCからhttps://mail.hoge.co.jp/api/reserve_countにアクセスするとstatus200 で Hello, this is the root path.という文字がかえる。

他だとstatus404 で 404 not foundという文字がかえる。

/api/reserve_count が呼ばれたときに実際に件数を返す処理を作る

response_content = b’Hello, this is the root path.’のところを件数返す関数に変更

してvi reserve_count.py し関数作る。例外処理ちゃんと入れていないので各自実装必要。

あんまり落ちなそうな気はするので実際には例外処理なしで突き進む。あと、ログイン代わりにquery_paramsみてパラメータがあっていたら件数確認処理呼び出すような緩いセキュリティ分岐を入れるつもり。

VSCodeのmarkdownlintの設定

直したこと

VSCodeにmarkdownlintの拡張を入れたらMD024 – Multiple headings with the same content と怒られた。マークダウン内に同じ見出し文言があると怒られるやつらしい。

章1ほげ

1-1.この章の概要

章2ふが

2-1.この章の概要

みたいに章をまたいで同じものを使おうとすると引っかかる。面倒なので停止。

直し方

VSCodeでCTRL+commmaから拡張機能のmarkdownlint->setting.jsonと選んで”markdownlint.config”: {        “MD024”: false    }を追加


    "editor.renderWhitespace": "all",
    "markdownlint.focusMode": false,
    "markdownlint.ignore": [],
    "markdownlint.config": {
        "MD024": false
    }
}

pythonのimport imaplibで日本語フォルダ名を使う場合はエンコードが必要

環境

  • PRETTY_NAME=”Ubuntu 22.04.3 LTS”
  • Python 3.10.12
  • pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)

手順

imap_toolsというのが楽らしいのでインストール

pip install imap_tools

インポートして実行

import imap_tools
mailbox_name = "INBOX.ジム.予約"
status, messages = mail.select(imap_tools.imap_utf7.encode(mailbox_name))

何もしない場合のエラー

mail.select(“INBOX.ジム.予約”)

として

yoshitake@mail:~/dovecot_delivery$ python3 test.py 
Traceback (most recent call last):
  File "/home/yoshitake/dovecot_delivery/test.py", line 15, in <module>
    mail.select("INBOX.ジム.予約")
  File "/usr/lib/python3.10/imaplib.py", line 756, in select
    typ, dat = self._simple_command(name, mailbox)
  File "/usr/lib/python3.10/imaplib.py", line 1230, in _simple_command
    return self._command_complete(name, self._command(name, *args))
  File "/usr/lib/python3.10/imaplib.py", line 987, in _command
    arg = bytes(arg, self._encoding)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 6-7: ordinal not in range(128)

ソース全体

import imaplib
import imap_tools
from email.header import decode_header

# IMAPサーバの設定
mail_server = 'mail.huga.co.jp'
username = 'hoge'
password = 'hugahuga'

# IMAPサーバに接続
mail = imaplib.IMAP4_SSL(mail_server)
mail.login(username, password)

# # メールボックスを選択
mailbox_name = "INBOX.ジム.予約"
status, messages = mail.select(imap_tools.imap_utf7.encode(mailbox_name))

# # メール検索(例: 未読メール)
status, messages = mail.search(None, "(UNSEEN)")
unread_count = len(messages[0].split())
print(f"未読メールの件数: {unread_count}")

# 接続を閉じる
mail.close()
mail.logout()