調べて、学ぶ

検索したり実験したことを覚えとくブログ

docomoのスケジュールアプリを移行した

docomoのスケジュールアプリはical形式じゃない

嫁さんがスマホを機種変したのですが、SIMはdocomoのまま、SIMフリースマホに変更しました。 googleアカウントもdocomoのメールアドレスも大したことなく移行できたのですが、まさかのスケジュールアプリで非常に困らされたので記録を残す。

前提

  • 嫁さんのスケジュールアプリはdocomoスマホのプリインストールアプリ
  • このアプリはdocomo以外のスマホではプレイストアからインストールできない
    SIMフリースマホではインストールできない

  • このアプリのバックアップ選択肢はdocomoクラウド or SDカードで、ファイル形式は(icalでもcvsでもcsvでもなく).vcs形式

  • SDにエクスポートしたvcsファイルのサイズは23MB(軽くめまいがした...)

  • 同じアプリは使えないため、これを機にgoogleカレンダーに行ってもらいたいが、googleカレンダーは.vcsファイルを受け取らない(インポートしても「0件中0件をインポート」となる)

試した手段

  1. vcsを扱えるアプリをインストールして使ってもらう
    ⇒ ない。 驚くぐらい見つからない。有料で対応しているようなことを書いているのもあるけど、どうも確証が得られない。却下。
  2. フリーウェアを探してvcsical変換をする
    • (フリーじゃないけど)outlookvcscsv変換
      ⇒ごめんなさい。outlook持ってないです。
    • MSNのoutlook.live.comからアップロード・icalでエクスポートできないか?
      ⇒ ファイルをアップロードしたらファイルサイズに引っかかった(10MBまでだった記憶)

いろいろググった結果、以下のが引っかかるが、どちらも希望は満たされず。

Q8.インポートできるファイル形式にはどのような種類がありますか。

iCalendar形式(.ics)とvCalendar形式(.vcs)に対応しています。iCalendarの文字コードはUTF8、 vCalendarの文字コードはSJISとなります。 

それだよ! と思わず声が出たのですが、実際に使ってみると「未来の予定しか登録しません」と言われてしまう。ぐむむむ...

で、何をしたか

今まで試したりググった中で分かったことは、

⇒自力でやるにはvcs形式とical形式の勉強が必要かと思っていたら、意外とこれはイケるかも... ということで、vcsから必要なものだけ別ファイルにコピーするスクリプトを作成。(nodejsです)

vcsの SUMMARY:スケジュールの題名 はQUOTED-PRINTABLEという形式でエンコードされている(初めて聞いた)とのことなので、これをデコードする機能がないか探したら、 そのものずばりが見つかったのでインストール。

◆プロジェクトフォルダ作成(コマンドラインで実行)

mkdir decodeVCS
cd decodeVCS
npm install quoted-printable

◆プロジェクトフォルダにdocomoスケジュールからエクスポートした.vcsファイルを置く

◆プロジェクトフォルダにindex.jsを作成し、コードを書く

// index.js
let quotedPrintable = require('quoted-printable');
let utf8 =require('utf8');
let fs= require('fs');

const path = require('path');

//変換対象(読み取り元)のvcs
const targetVCS = '(vcsファイルの名前).vcs';

//変換先(フォーマット後)のvcs
formatedVCS = 'newVCS.vcs';

//prodID('//会社名//個人名(プロダクト名)//国名' らしいけど、ブランク以外ならなんでもいい)
const prodID = '//-//baba babao//JP';

//vcsを読み込む
const text = String(fs.readFileSync(path.join(__dirname, targetVCS))).split('\r\n');

//読み込んだ内容によってはスキップすることもあるため、ストリームを使って書き込む
const writeoption ={
  encoding:'utf8'
}
const writeStream = fs.createWriteStream(path.join(__dirname, formatedVCS),writeoption);


let arrline;
let doFlg = true;
let strtmp ='';

//読み込んだvcsを1行ずつ展開
//日付がない場合は書き込みをスキップする
text.map(line =>{

  arrline = line.split(':');

  switch(arrline[0]){
    case 'BEGIN':
      if(arrline[1] === 'VCALENDAR'){
        //icalファイルのヘッダ
        writeStream.write(line + '\r\n' + 'PRODID:' + prodID + '\r\n' + 'VERSION:2.0\r\n');
      }else{
        strtmp += line + '\r\n';
      }
      break;
      
    case 'DTSTART':
    case 'DTEND':
      if(arrline[1]==='')  {
        //日付が入ってなければこのイベントは書き込まない
        doFlg = false;
      }
      
      strtmp += arrline.join(':') + '\r\n';
      break;

    case 'CATEGORIES':
      strtmp += arrline.join(':') + '\r\n';
      break;
      
    case 'END':
      strtmp += arrline.join(':') + '\r\n';
      
      //有効なイベント(DTSTART、DTENDがある)なら書き込み
      if(doFlg){
        writeStream.write(strtmp);
      }

      //初期化
      strtmp = '';
      doFlg = true;
      
      break;

    default:
      //'SUMMARY;'から始まる場合は加工
      if(arrline[0].search('SUMMARY;') === 0){
        //quotedPrintableをデコードし、改行を文字を半角スペースに変換
        //arrline[0]は 'SUMMARY;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE' となっているので、SUMMARY以後をカットして「:」付ける
        strtmp += 'SUMMARY:' + utf8.decode(quotedPrintable.decode(line.split(':')[1])).replace(/\n/g,' ') + '\r\n';
      }
  }
  
})

writeStream.end();

新たにnewVCSというファイルを作り出すので、そいつをgoogleカレンダーにインポートさせたら...読んだーーー!

嫁さんもこれで満足だろ...と思ったら、「今まで色分けしてたのに全部同じ色になっている」とのクレーム。 色の設定はical形式で定めていないので、次のレベルへチャレンジですわ…。

firebaseの「web設定」ボタンが見つからない

あるはずなのにない

初めてfirebaseを触るため、本を見ながら言われるままに画面を進めるのですが… authenticationの画面にあるはずの「web設定」のボタンがない。

f:id:docoka_dareka:20210417213948p:plain
webアプリ設定がない

”firebase authentication web設定 ない” でググっても引っ掛からず。

これが押せないとAPIキーが発行できないのぢゃーー としばらくコンソールを探すと、プロジェクトの設定画面にこんなのを発見。

f:id:docoka_dareka:20210417184819p:plain
firebase-webアプリ設定

アプリがない…からボタンがない というわけか。 ここにある”</>”をクリックしたらプロジェクト発行画面になり、

f:id:docoka_dareka:20210417185208p:plain
web設定画面

「アプリを登録」すると… おー、これこれ。これが欲しかった。

f:id:docoka_dareka:20210417185636p:plain
webアプリのapi発行

いつ変わったのか知らんけど、なかなか見つからなかったのでメモっとこ。

crontabの実行

定時にコマンドを実行したい

crontabを仕込む

windowsならタスクスケジューラに登録するだけでOKなことが、ラズパイではcron(クロン)になる。ラズパイ(手元のはラズパイ4)ではcronはどうやらデフォルトでonになっているようなので、あとはログの設定を。 インターネッツはなんでも情報が転がっていて便利だねぇ。

ラズベリーパイでCronを使って定期処理を行う方法、ハマりポイントやCronが動かない場合の対処方法など

これで終わりではなく、ログの書き方も要設定。

crontabのログに日時を仕込む

上記のcrontab設定だけだとログ(/var/log/syslog)に「やった」としか残らないので、もうちょい詳しい内容が欲しい。(errorだけじゃ何が起きたわからないし)

crontab の設定で日付の入った名前のファイルをつくろうとしたらエラーでたよ

コマンドの出力をリダイレクトして、日付をエスケープしろ、と。 つまり、

0 0 * * * (コマンド) > /home/(ユーザ)/`date +%Y%m%d`.log

てことか。(ちゃんと動きました ^^)

またoffice2013にやられた

【困りごと】

powerpointでナレーションした音声が聞こえない

【結論】

mp4コーデックがPCに入ってなかった。

【環境】

以前の記事を参照。 sirabete-manabu.hatenablog.com

【調べたこと】

  • ナレーションが聞こえるPCはoffice2013、聞こえないPCはoffice2010…またか。

  • 該当ファイルの拡張子を.zipに変えて解凍してみると、音声ファイルは「.mp4」

  • 聞こえるPCも聞こえないPCも、mp4は再生可能(GOMプレイヤーで再生している)

  • 聞こえないPCで該当ファイルを開き、ナレーション再生箇所(音声のアイコン)にカーソルを近づけると、「対応していないコーデック」との表示

…いやいや、対応してないコーデックなら再生できないでしょ(GOMプレーヤーあるし)、としばらく考え込んでいると、後輩くんが「QuickTime入れればいいってグーグルさんがいってますよ」と。

なるほど確かにmp4といえばQuickTime。でもすでに再生できてるしなぁ… でも言われたことは否定せずにとりあえず試してみよう。

で…解決! 思わず後輩くんに”ジーニアス○○(後輩くんの名前)!”って叫んでしまった。

【何が起きたのか(おそらく)】

あとで裏どりもできたけど、

  • PowerPointのナレーションは、
    • デフォルトはwav形式で作られる
    • office2010のpowerpointは、メディアを圧縮するとwmaになる
    • office2013のpowerpointは、メディアを圧縮するとmp4になる

support.microsoft.com

おそらくは、ユーザーはpowerpoint 2013でナレーションを吹き込んだ後、ファイルサイズがでかすぎて圧縮をかけたと思われる。 その結果ナレーションにmp4を使うファイルが出来上がり、mp4コーデックを標準搭載していないwin7&office2010の組み合わせではエラーになったと思われる。

GOMプレーヤーはmp4を使えるけど、プログラムの埋め込みじゃなく音声の埋め込みをしたから関連付けは無視されていたとも考えられる。 win10だったらこの現象も起きなかったんだろうけど…😩

はーどにんぐにまた行ってきた(2回目)

2020/11/13から14にかけて、Hardening2020 H3DX という競技会に参加したのでそのメモ。(2回目。1回目もまとめたけど、ブログじゃなくスライドなので非公開です…)

ハードニングとは


wasforumという団体が主催する、2日間にわたるイベント

◆1日目 Hardening Day

  • 1チーム9~11人(ほぼ面識なし)で
  • 脆弱性のあるショッピングサイト(仮想)を整備し、攻撃から守る
  • 1日(8時間)守り切って売り上げ立てる
  • 守る対象の情報は競技前日の夕方配布 → 翌日までにURL、サービス構成、ユーザ名、パスワードなどを頭に叩き込まなければならない
  • 相手は運営陣の凄腕ハッカー集団 → 防御が甘いサイトは即改ざん・ダウン
  • 現実世界に即し、WAFやアンチウイルスソフト、セキュリティ企業のアシストなどを受けることが可能(マーケットプレイス:MP)

◆2日目 Softening Day

  • 事前にやってきたこと、1日目にやったこと、その結果得たもの・ことをチームごとに発表
  • 1日目に起きた出来事について一部ネタばらし
  • なにが辛いって、この発表をするために資料を作らなければならないこと=1日目の競技中にドキュメントを作る資料を集めなくちゃならない

この内容の濃さから 一部では「セキュリティ業界の精神と時の部屋」とも呼ばれている

…と、どう考えても弁慶の立ち往生しか想像がつかない「死にゲー」競技です。

誰が行くの?(参加資格)


基本的に資格は不要で、情報セキュリティに興味がある人は誰でも応募可能です。大半はなんらかの技術畑にいる人ですが、他チームには弁護士も。あとは学生かな。若い力はいつも目覚ましい✨

なんで参加するの?


なんででしょうね。やると楽しいんですよ。ゲームだから。 でも、あとから聞いた話だと、「自分が何も出来な過ぎて、帰ってから泣いた」とか「とてつもなく濃厚な時間を過ごした」とか言われてるみたい。自分も2回目だけど、この濃さは大人になってからは、なかなか味わえない。

準備期間1か月程度の即席チームだけど、当事者にとっては青春ドラマなみの熱量なのです。

初参加のチームメンバーに参加理由を聞かれて「楽しいから」と答えたら「マゾですね」と言われたことは鮮明に覚えている。

はじまりのきっかけ


前回(2019 SU)ですっかり面白さに取りつかれてしまい、今年のオンラインイベントにも参加していたら「今年のhardeningはアーリーバード枠(先着優待みたいなもん)があります」と聞いたので急いで応募したら、通ってしまった… f:id:docoka_dareka:20201119005136p:plain

今回のチーム


気の利いた人(のちにチームのCFO[財務担当])がslackを作り、みんなに声かけ。いま改めて読み返すと、

  • セキュリティエンジニア
  • サーバいじりながらセキュリティ な人
  • インフラいじりながらセキュリティ な人
  • 開発者
  • 情シス

の10名で構成されたチームで、windowsユーザを公言しているのは自分含め二人。 オペレーションはみんなにお任せして、自分は裏方になることを決心。

※この時点でもう本番まで1ヶ月切ってます。

当日までにやったこと


1. 運営側から「すぐにやれ」と指示されたこと

チーム名と役職(CEO:社長、CFO:財務担当、COO:オペレーション担当)、体制図を決めて、提出する。

→【チーム名】ISUCONジェネレータでぽちぽち押していき、一番盛り上がった名前「おにぎりまみれ」

→【役職】当日の役割がわからないので”なんとなく”で決定。個人的には技術面がまったく心許ないので、技術チームは避けとこうと思い、恐れ多くもCOOを拝命しました。(でも技術チームの上らしい)

→【体制図】ドキュメント作成のエキスパート(と私が勝手に思っている)のメンバーが、Meetで画面共有しながらその場で作成 ※ロゴは翌日でした(それにしても早っ)

f:id:docoka_dareka:20201121181041p:plain
おにぎりまみれ体制図

2. ひたすらにミーティング

2−1. 情報共有

ぐだぐだになった会も多いですが、自分含む経験者が「本番接続環境」「守る対象(会社・ショッピングサイト)の規模」「本番で起きた攻撃・トラブル・イベント」などをメンバー内でQAやら情報提供し、とにかく共通認識を積み上げる。んで、体験者の情報を基にスタートからの作戦を立てる。”死活監視スクリプト準備してslackに送る”、”パスワードはバラバラにして、コピペで”など。

…が、ここにすでに例年との違いが…

2-2. 書類を準備する。

”そんなものまで!?” とも言われそうですが、仮想であっても”会社”なのです。そして、スタート直後はその書類さえもない(会社としてまず信用されない)状態なので、評価を得るためにはこれも整えなければならない。当日にやってたらあっという間にタイムアップなので事前準備が必要なのです。自称"裏方"の私と、前述の「ドキュメントのエキスパート」、CEOがコンテンツを準備。

以下、全部明かすと次回以降に使われちゃうので一部抜粋。

  • 会社概要(CEOが考えた)
  • プライバシーポリシー
  • 特定商取引による表記
2−3.環境を揃える

今まではオンサイトで沖縄・淡路島・札幌とやってきましたが、今回は初めての”完全オンライン開催”なので、チームメンバー全員がテレワーク状態で参加します。

運営側が用意したコミュニケーション環境(zoom、discord、念の為slack)を滞りなく使えるように、あらかじめインストール&ミーティングで使い込む。discord初めて使った…

あとでCEOが数えてくれましたが、毎週2回程度を繰り返し、本番までにトータル9回のミーティングをしたようです。

前々日


運営からCEOに事前課題が出される。

"他のチームのCEOと協議して、セキュリティ業界が直面する課題について政府・関連団体への提言をまとめよ”

この日の23時、早速各チームCEOが会談したそうです…

CEOからCOO=私に課題が出される

"当日の公式サイト(swapcardで運営)にチーム全員が入れるようにメアドを集めて提出せよ。 ただし、すでにアカウント所有している人のぶんの新たなアカウントを申請しないようにしてください。"

さりげなく”今日中に”という圧を受けながら順調に集まるメールアドレス。

f:id:docoka_dareka:20201121230822p:plain
swapcard

時間は迫れど反応がないメンバーが3人。頼む、返事してくれ〜と願いつつも日付が変わりそうだったので、過去の自己紹介を基に独断でアドレスを提出したのが23:59の滑り込み。結果としては予想が当たり重複なく登録できたけど、外れたらと思うと恐ろしい。というか、業務としてこの行動は絶対にとりたくないし、心臓に良くない…

f:id:docoka_dareka:20201121232627p:plain
swapcard2

前日


夕方に当日の環境資料が届きます。 ここから競技が始まっていると言っても過言ではないので、職場を早退(ズルではないですw)して準備します。 この時間にやっとswapcardの案内が来る。(前日の独断のため、「きたよ」と連絡をもらえるまでずっとドキドキしてた…)

ここで罠が発動。毎年ならば、踏み台環境にsshで接続し、その先にある競技環境にポートフォワードしてリモートデスクトップsshで接続していたのですが、いきなりその前提が崩される。(下図)

f:id:docoka_dareka:20201122000629p:plain
競技環境への接続

「Guacamole」が読めず、「ぐあかもーる?」「ぐぁかもーれ?」と混乱を来たし、どうやらssh接続できない=あらかじめ考えていた作戦が使えない という事態に。技術チームが1時近くまで作戦を立ててました。

前日に行ったこと


1. サーバにログインするユーザを割り振る

ログインユーザがバッティングしないように割り振り。

2. キャッシュフローを決める。

繰り返しますが「会社」なので、勝手に備品を買ったり商品在庫を増やしたりしないよう適切なルールを作り、いざという時に説明できるようにしなければなりません。

なので、CFOが稟議テンプレートを書いてくれました。 …が、本番で舞い上がった私はすっかりそれを忘れてslackで直に稟議あげ→CFOに決裁依頼という掟破りをしました。記憶にあるだけで3回ぐらい😰 ごめんなさい。

3. 商品説明・画像を準備

毎年ころころと競技開催地の名産品を準備するのですが、初のオンライン開催の商品はなんと…サブスクリプション

タイトルに合いそうな画像や説明文を作り上げ、当日ショッピングサイトにアップロードする準備を行う。

4. マーケットプレイス(MP)で買う物の選定

MPでは、本物の企業が本物の製品・サービスを競技環境に持ち込んで取り付けてくれます。これにより、 - 参加者はゲームを有利に。かつ、実際に使った評価ができる - 出店企業はコマーシャルになる=うまくいけばリアルな世界で商談に… ということができますが、競技者は勝ちに行くので真剣にモノ選びします。

私がいるチームはCiscoのFW/IPS&EDR、あいおいニッセイ同和損保のサイバー保険に狙いを絞りました。(この2品、両方ともネタになります)

いざ、当日へ。

当日 -Hadening Day-


全員がdiscordに入り、9時開会式:楽しい寸劇などを交え、競技背景・ルールの説明、9時半スタート。怒涛のトラブル祭りの始まりです。

この日起きたこと(今後のため、詳細は伏せます)

1.競技環境に入れない

 あるあるですが、今年もいきなり阿鼻叫喚。Guacamole(ワカモレっていうんですって)のURL叩いたけど、証明書エラーで先に進めない人が続々。    他のチームが足止めを食らっている間に、こちらはMPの入札締め切りに滑り込みセーフ&Cisco購入権Get!    サイバー保険は入札不要(全員買えます)とのことで、急がなくてもいいじゃん と購入見送り ←トリガー設置

2.CEO インタビュー

各チームのCEOが意気込みをインタビューされます。 うちのCEOは「まぁ3億くらいは売り上げたい」と…

3.Zoomのブレイクアウトルームに入れない

 この競技の恐ろしいイベントで、情報漏洩した際に「呼び出し」があります。オンサイト開催の時はチームのCEOが監督官庁のところに行って、対面で詰められますが、今回の呼び出しはZoomのブレイクアウトルーム。Zoomにそんなメニューないよ!と悲鳴をあげる人多数。私もその口でしたが、お昼休み中にzoomをverUPしたら出てきた。 最新版、ダイジ。

4. webページ改ざんされる

 前回やmicroHardeningで免疫がついてますが、やはりここでも起きる。CFOが速攻で着手し、30分程度で回復。てゆうか、CFO …仕事の幅広すぎ。

5. httpやたら落ちる。

 原因不明なままメンバー1人が張り付いていたけど毎分起動するようcron設定して対応

6. サーバの証明書の期限切れ

 タネは言わないけど…気づかんわ。

7. お漏らし(DB持ってかれた)

何もいうまい…  

f:id:docoka_dareka:20201123094210p:plain
db窃取

※このペナルティ(補償)で、売上が3000万ほどマイナスに。

8.詰められる

7について、運営(親会社という設定)から「1時間後に役員会議するからCOO(=私)はZoomブレイクアウトルームに来い」とのお達し。こんな人たち相手に…

いわく、

  • 3億売り上げるんだよね? どんな計画で?
    • 2参照。
  • 会議だよね? 資料は?
    • メンバーに情報収集してメモしてましたが、無手で行きました。(zoomの画面共有とか準備すべきだったのね…)
  • 漏洩したのか…保険とか入ってないの?
    • 1参照。

…言い訳しようがないほどの正論でマウンティングされました。

相手が悪い人じゃないことは知ってるし、その上でアメとムチの小芝居を見せられると笑いたいけど笑えない😫

17時まで猶予をもらい、報告資料を提出することを約束しました。

(番外)試合終了までに行うミッション

競技中にやったことを資料にして運営に報告。技術の人たちにはガードに集中してもらいたいので、ここは裏方のお仕事。 達成状況を確認し、やってないことがあればお願い、足りない資料があればスクショをお願いして撮ってもらったり。(他力本願)

1日目終了


競技は終了後は2日目に備えた「発表資料作成」があります。ここで自分にできることはなんだろ? と考えると大したことが思いつかなかったので、PDFで出されたテンプレートをgoogledocに清書し、自分で書けるところだけ書いて、「あとは各々が思い当たるところを埋めて」 とslackに投げる。

2日目 -Softening Day-


各チームがこれまでを振り返り、まとめた資料を発表する。

その様子はこちら。(35分44秒から) H3DX softening

この1ヶ月の記録が10分のスライド発表に凝縮される瞬間です。 発表はこのチームのロゴを作ってくれたメンバー「のみぞー」さん。

nomizooon.hateblo.jp

ほかのチームも見ていましたが、10分ピッタリで発表したのは彼女だけではないかと。ロゴといい文書作成といい、発表といい、才能の塊かよ…と目をハート😍にしてました。

全チーム発表後、運営側での状況(競技開始までの運営努力、攻撃時にここを狙った)、各チームがどんなことをしてきたか を経て、スコアの結果発表。 チームおにぎりまみれの結果は… 優勝!!

f:id:docoka_dareka:20201123151627p:plain
優勝発表前のざわざわ

※名前にちなんで”おにぎりポーズ”してますが匿名処理で。

f:id:docoka_dareka:20201123143536p:plain

やった。やった。二度目の出場でまさかの優勝!

自分はテクニカルなことは一切してないけど、仲間がいれば、自分ではできないことも誰かがやってくれる。 のみぞーさんのブログにもあるけれど、

  • 「できてないから手伝って」「しくじった、直した」と素直に声を出せたこと
  • 声を出しやすい環境を作ったこと(反応する、怒らない、否定しない)
    • メンバーのあんずさんは年上だらけのこの環境で物怖じせずに質問・発言されてました。 知らない人って年上なだけで変なプレッシャーかかるから、これは1ヶ月通してのファインプレーだと思う。

最近の良かったこと(Hardening 2020 H3DXでチーム優勝したりFun Pay!に寄稿をした等) - 桐生あんずです

が迅速な対応につながったのだと思います。(みんな優しい人たちだった)

いぢられ役になってくれたCEO(わざと?)、マルチに働くCFO、対外対応バッチリのコンテンツ担当、報告もアクシデントも高速対応の技術チーム。みなさんのおかげでとてもいい体験ができました。 この場を使ってお礼申し上げたいと思います。

ありがとうございました。

登録情報処理安全確保支援士(RISS)をやめた

登録情報処理安全確保支援士(RISS)という資格をもっていたのですが…

この名前でピンとくる人は、これから何を書くかある程度予想済みだと思いますが、 情報処理試験に”情報処理安全確保支援士”という工事現場にでもいそうな資格があります。 とにかくそんな名前の資格を持ってたのですよ。最近まで。

 古くは”セキュリティスペシャリスト”とか”セキュリティアドミニストレータ”とか”テクニカルエンジニア(情報セキュリティ)”なんてキラキラな名前がついていたのですが、いままでこんなに何度も名前が変わった試験なんてあったのだろうか…

 大して勉強しなくてもイケんじゃね? と高をくくって不合格になったのが10年以上前で、むきになって何度も受けなおしてやっと合格したのが2017年(一応試験にエントリーしてから職場の行き来の間くらい勉強しましたw)。

 やっとひと段落したと思っていたところに今度は「また名前変えるよ~、今度は任意で登録制だよ~」とのお知らせが来て、よくよく詳細を読んだりググったりすると、

・1年ごとに更新するものである
・登録時、更新時に手数料がかかる
・登録時:ざっくり1万円強(もう調べるのも面倒だ…)
・更新時:1年ごとに2万円払ってオンライン講習(その後テスト)をする。3年ごとに集合講習があり、8万円

→初年度:登録費+講習費=3万、2年目:2万、3年目:2万+8万= 最初の3年間で15万強かかる。(※その後の3年は登録費抜きなので14万)

・最近「ライセンスカード」のようなものを作ったらしい。
・いわゆる「士」業(弁護士・会計士のように、資格があることで業務を行うことが許可される仕事)
・しかし、現時点で「この資格がなきゃできない仕事」はない

とまぁ、どう考えてもメリットが薄い、むしろ私にとっては、ほかの資格と大して変わらないのにやたらとお金がかかるイメージしかないのです。

職場にも一応そっとアピール(1年ごとに”金かかる資格持ってるから補助してください”)もしているのですが、”それって何?”と聞かれることもなく、ただの資格カウンタ+1の扱い。 なので、将来への期待を込めて自腹で2年間維持・更新したのですが、今年はいよいよ3年目。恐怖の10万円上納です。

このお金があれば、あれ(例えばmacbook買う)もこれ(例えば車検の足し)もできるし、それを我慢してまで更新して得られるものって何だろう?と考えた結果、「こりゃダメだ」となりまして。

コロナウイルスの影響で集合研修が中止・再開・また中止と目まぐるしく変わってますが、おそらくなんらかの方法で上納するという状況は変わらないでしょう。 よくよく考えたら、こんなにお金払うよりも、毎年試験を受けて再登録する方が全然安上がりではないか ということに考えが至りまして。

こちらにある「登録消除届」を印刷してIPAに届けました。2週間ほどたった本日、登録者のリストを確認したところ自分の名前が消えたので、無事に資格が削除されて”野良”情報処理安全確保支援士になったようです。 なんか野武士みたいでこっちの方がいいかも。

それにしても… これはとても共感した。 いや、まったくそのとおり。ある意味これを読んだおかげで踏ん切りがついた気がする。

www.orangeitems.com

googleAPIを駆使するLINEbotサービスを作った #3

前回の続き

2.分解した内容をgoogleカレンダーに登録する

gMailのテキスト取得がうまくいったので、取得した文章をgoogleカレンダーのパラメータとするよう分解していく。

メール例文

予約通知です

施設名: aaaaaaaaa

スタート: 2020年 7月 1日, 水曜日

エンド: 2020年 7月 5日, 日曜日

予約ID: nnnnnnnnnn


受信するメールは定型文(以下)なので、「:」ごとに分解していけば良い。

こんな感じ。(ソースから引用&若干編集)

//メールの文章を分解してパラメータに格納する
//引数 pText:メールのテキスト内容

exports.sliceText = function(pText){
    let textlines = pText.replace(/\r/g,'') //改行ごとに配列化
    let params;
    let cnt;
    let YMD;
    let dt;
    let job = {'dtFrom':'','dtTo':'','youbi':''}; 
    let reserveID;

    //改行ごとにメール文章を
    for(cnt in textlines){
    
      params = textlines[cnt].split(':')
      switch(params[0]){
        case '施設名':
          room = params[1].replace(/ /g,'');
          break;
        case 'スタート':
          dt = params[1].replace('/ /g','').replace('年','-').replace('月','-').replace('日','');// y-m-d, ◯曜日
          YMD = dt.split(',')[0].split('-');
          stay.dtFrom = new Date(YMD[0], Number(YMD[1]) -1 , YMD[2] ,12,00,00);
          break;
          
        case 'エンド':
          dt = params[1].replace('/ /g','').replace('年','-').replace('月','-').replace('日','');// y-m-d, ◯曜日
          YMD = dt.split(',')[0].split('-');
          
          stay.dtTo = new Date(YMD[0], Number(YMD[1]) -1 , YMD[2] ,10,00,00);
          
          //清掃予定(時間は任意で固定)
          jpb.youbi = params[1].split(',')[1].replace(/ /g,'').substr(0,1);
          job.dtFrom = new Date(YMD[0], Number(YMD[1]) -1 , YMD[2] ,10,00,00);
          job.dtTo = new Date(YMD[0], Number(YMD[1]) -1 , YMD[2] ,11,00,00);
          
          
          break;


        case '予約ID':
          console.log(params[1])
          reserveID = params[1].split('ref')[0];
          break;
      }
    }

    //googleカレンダー用のパラメータを返す
    return {'room':room,'job':clean,'reserveID':beds24ID};
};

googleカレンダーについて。 先のsliceText()をよしなに加工して、以下のinsertEents()の引数として渡すとイベントが作成できる。(認証周りはgMailと同じ)

//◆◆GCal予定書き込み◆◆
//◆◆insertEvents()に使用するパラメータ
/* {
  start:{dateTime:'',timeZone:'Asia/Tokyo'}
  ,end:{dateTime:'',timeZone:'Asia/Tokyo'} 
  ,summary:'カレンダーのタイトル'
  ,description:'カレンダーのメモ'
  ,location :'カレンダーの場所'
} */
exports.insertEvents = function(pGcalParam){
  return new Promise((resolve)=>{
    // Authorize a client with credentials, then call the Google Calendar API.
    resolve(authorize(JSON.parse(credDat)))
  }).then((res)=>{
    const oauth = res

    return new Promise((resolve)=>{
      const calendar = google.calendar({version: 'v3', auth:oauth});
      calendar.events.insert({
        calendarId: 'primary',
        resource:pGcalParam,
      }, (err, res) => {
        if (err) return console.log('The API returned an error: ' + err);
        
        //console.log(res.data.id);
        resolve(res);
      });
    })
  })
};

(後々で必要になる)カレンダー内容の更新について。

このLINEbotは「仕事が来たぞ」というお知らせについて「やります」と返事した時にカレンダーの更新(担当者名を書き換える)を行うので、googleカレンダーの更新が必須になる。 APIのリファレンスをぱっと見た感じだとupdate()を使えばいいじゃないの? と思いがちですが、部分的な編集の場合はpatch()を使うらしい。 渡すパラーメータも上のinsertEvents()で使っているものと同じなので、上記の「calendar.events.insert」の部分を「calendar.events.patch」と書き換えるだけでOK。

※一意のイベントに絞り込まなければならないので、カレンダーのIDは必須。 処理のフローとしては、

1.予定の一覧(ID)を取得

2.1をループし、LINEbotから与えられたカレンダーと同じIDが見つかったら内容更新

となる

(ソース抜粋)
//現在の予定一覧を取得(gCalendar.listEvents())し、対象のイベントが未登録であればreplyユーザ名で更新する。
gCalendar.listEvents().then((ev)=>{
    if(ev.length){
        ev.map((ev)=>{
        
        if(ev.id == [LINEbotで募集しているID]){
            //カレンダーのサマリー(担当者を格納している)内容を確認
            if(ev.summary == '未登録'){
            
                //登録
                const gCalParam = {
                    summary: 【LINEのユーザ名】
                    ,id:e.id
                }
            
                entryEvents(gCalParam).then((res)=>{
                    //略
                });

            }else{
                //誰かが登録済み
                let echo='';

                if(ev.summary == 【LINEのユーザ名】){
                    //自分が予約済み
                    //略
                }else{
                    //自分以外が予約済み
                    //略
                }
            }
          }
      });

  }else{
      console.log('no events')
  }
});

function entryEvents(gCalParam){
  return new Promise((resolve)=>{
    // Authorize a client with credentials, then call the Google Calendar API.
    resolve(authorize(JSON.parse(credDat)))
  }).then((res)=>{
    const oauth = res

    return new Promise((resolve)=>{
      const calendar = google.calendar({version: 'v3', auth:oauth});
      
      //patch()で更新。eventIdにカレンダーのIDを指定するのがキモ
      calendar.events.patch({
        calendarId: 'primary',
        eventId:pGcalParam.id,  
        resource:{summary:pGcalParam.summary}
      },(err,res)=>{
        if (err) return console.log('The API returned an error: ' + err);
        
        //console.log(res.data.id);
        resolve(res);      
      })
    })
  })
}

これで「メールを受信」して「カレンダーに登録する(更新する)」ことができた。

#4.LINEの配信・メールの処理へ続く ...続かせるのやめました。

(追記)2020/11/18 気力が持たないし、これからやることもそんなに面白くないのでここで打ち切ることにします。