糞コードのリリースは許されるのか?

糞コードをリリースすることの是非みたいな発言をXで見かけたので私見を纏めておく。

糞コードの問題は、理解するのに時間が掛かるとか、改修が困難とか、バグを出しやすいとか色々と言われるけど、纏めるとランニングコストが高いと言うことになる。単純にコードの保守性だけの問題では無くて、処理が最適化されていないために多くのコンピューターリソースが必要となるといった事も含まれます。

ランニングコストが高いと何が不味いのかを、簡易的にグラフにしてみた。

時間経過とともに機能が追加されたりデータが増えたりするため、システム規模は日に日に大きくなり、累積コストは指数的に増加していきます。糞コードは初期コストが安くても運用コストが高くなります。対してクールコードは初期コストが高くても運用コストが低く抑えられています。初期は糞コードの方が運用コストが低く済んでいますが、いずれクールコードと逆転するわけです。

糞コードの収益性が悪いだけなら良いのですが、場合によっては採算ラインを超えてしまう事が起こります。独占企業なら問題にならないかもしれません。ですが競合他社が居る場合、運用コストの高さは長期的にビジネスの継続を危うくするわけです。

糞コードは後で書き換えれば良いという主張もあります。ビジネスとして継続する為に、システムを再構築してクールコードに書き換えるわけです。ですがこれは開発コストを二重に負担しているので、コストが大幅に増えて収益を圧迫します。

特に新規のビジネスの場合には資金的にも人員的にも余裕がないため、実際には糞コードの再構築は後回しになりがちです。再構築が遅延すると、その間にコードもデータも増えていくため、再構築にかかるコストがより大きくなります。最悪の場合、再構築を行うと採算ラインを越えるため出来ないが、このままだと運用コストが採算ラインを越えるため放置も出来ないという、詰んだ状態に陥るわけです。

以上のことから、糞コードのリリースについて三行に纏めておく。

  • 時間的な制約から糞コードをリリースする場合はあり得る。
  • だが糞コードは最小限にし、速やかに改修しておく必要がある。
  • 糞コードの放置はビジネスを終わらせる時限爆弾となり得る。

画像ファイルを開こうとすると「ファイルシステムエラー ファイルを読み込めません」となる。

MicrosoftフォトなどのMicrosoft Store アプリが動作しなくなると中々に厄介です。昔同様の状況になったときには修復できずに終わったのですが、今回はなんとか修復できたので実行した作業を纏めて起きます。

DISMコマンドおよびsfcコマンドでコンポーネントストアの修復を試みます。管理者権限でコマンドプロンプトを開いて、以下のコマンドを順番に実行します。

DISM /Online /Cleanup-Image /CheckHealth
DISM /Online /Cleanup-Image /ScanHealth
DISM /Online /Cleanup-Image /RestoreHealth
sfc /SCANNOW

次に設定→更新とセキュリティ→トラブルシューティング→追加のトラブルシューティングからWindowsストアアプリを選んでトラブルシューティングツールの実行を行います。

設定→アプリ→アプリと機能からMicrosoftフォトを選択して詳細オプションを開く。終了、修復、リセットを純に実行する。

Microsoftフォトが起動するようにはなりましたが、アプリと機能に表示されないなどどこか動作が不自然なのでPowershellからMicrosoftフォトをアンインストールします。

管理者権限でPowershellを開いて以下のコマンドを実行します。

Get-AppxPackage Microsoft.Windows.Photos | Remove-AppxPackage

Microsoftストアを開いてMicorosftフォトを再度インストールします。

参考:ファイルシステム エラー-2147219196の対処法7つ

VBAはオワコンなのか?

VBAがオワコンなのか?という話題がTwitterで流れていたので、私の考えを纏めておこうと思う。

VBAの生い立ち

Visual Basic for Applications(以下VBA)の話しをするときに、Visual Basic(以下VB)のことを抜きにすることはできません。VBAは、いまはサポートが終了しているVBという開発言語を元にして生まれました。VBは、いまもMicrosoftが提供しているVisual Basic.NET(以下VB.NET)とはまったく異なる開発言語です。VBはWindows専用の開発言語として広く支持を集めました。その開発の平易さから、特に受託開発の現場で多く使われてきました。利用者がが増えれば、対応する事業者も増えます。多くのサードベンダーがVB用のコンポーネントを提供しており、当時としては開発しやすい環境が整っていたのです。

VB最後のバージョンとなるVB6.0はComponent Object Model(以下COM)に準拠し、Microsoft開発言語の中核となりました。どのような言語であってもにCOMに準拠したコードを書けば、使用する言語によらず機能を呼び出せるようになります。オーバーヘッドも比較的小さく、単にライブラリを呼び出せるだけでは無く、プロセス間の通信や、ネットワークを介してサーバー間の呼び出しも行えるものでした。多くのコンポーネントがCOMに準拠したものに置き換わり、様々なサードベンダーが提供するようになっていきました。

ところがその後にCOMの欠点が問題になっていきます。VB 6.0の発売された1998年はインターネットの黎明期にあたりました。今ほどセキュリティへの要求は厳しくない時代に設計されたため、セキュリティへの設計面での配慮がほとんど無かったのです。Microsoftはその後に多くのセキュリティ問題に苦しむことになります。

VB 6.0の発売から4年後、セキュリティを強化して再設計したVB.NET 7.0がリリースされます。Microsoftはそれまで、二年ごとに新バージョンを提供していたことを考えると、相当に苦労したことがうかがえます。ですがVB.NETにはVB6.0との互換性は全くありませんでした。互換性の問題からVB6.0からVB.NET7.0への移行は進まず、Windows 11となった今もVB6.0のランタイムライブラリがOSと共に提供され続けています。

VB.NET7.0が発表された後、当然ながらVBAについても多くの議論が巻き起こりました。セキュリティを考慮するならVB.NET7.0を基礎としたものに作り替えた方が良いのは分かっています。でも現実問題として互換性の全くない言語への移行は困難を極めるのは明らかでした。それに対する結論として現在の状況があります。

MicrosoftはVBAはその互換性を維持して提供し続けることを選択しました。同時に、セキュリティの問題に対応するためにデフォルト設定ではマクロ機能を無効にし、また電子署名を付けた出所の明確なマクロ以外では警告を表示するようにしました。拡張子もxlsx(マクロ無し)とxlsmx(マクロ有り)と分ける事でユーザーがマクロの有無を意識しやすくしました。ユーザーはマクロを利用するために設定を変更する事になりますが、それに伴うリスクはユーザーが負うものとなりました。

最近でもセキュリティ強化は続いていて、インターネットからダウンロードしたファイルや、共有フォルダ上のファイルについては、デフォルトではマクロが実行されないような改善が行われています。

VBAに変わる機能を提供する試みも繰り返し行われています。ファイル仕様が公開されオープン化したことにより、xlsxファイルを編集する事のできるライブラリが様々な言語で利用できるようになりました。またOffice製品を操作するために、Microsoft Office Interop、Visual Studio Tools for Office、Apps for Office、Excel REST APIと何度か新たなツールを提供を試みていますが普及には至っていません。Windows OSに比較的容易に使える開発言語としてPythonを組み込むと言ったことも行われています。最近あらたに提供しているのはPower Automateですね。

VBAを使い続ける事の何が問題なのか?

セキュリティ上のリスク

マクロの実行を許可することに伴ってキュリティリスクが発生します。VBAが含まれたファイルがコンピューターウィルスの感染経路となっている事は知られていることと思います。リスクを認識して電子署名の無いマクロの実行を禁止する等の対策を取っているなら良いのでしょう。ですが、VBAを使っている企業では利便性を優先して、どんなマクロも実行許可しているのが実情でしょう。

機能面の貧弱さ

VB6.0の頃には様々なベンダーがCOMコンポーネントを提供していました。これにより2008年頃までは拡張性の高いパワフルな言語となっていましたが、今は殆どのベンダーがCOMコンポーネントの提供から撤退しています。VBAで出来る事が縮小していっているのが実態です。

VBAの言語機能どのものの拡張も20年単位で行われていません。この20年間で多くの言語に取り込まれてきたような機能、完全なオブジェクト指向や無名関数、並列化などの機能が追加される見込は無いでしょう。ソースコード管理システムとの連携が極めて困難なのも生産性を大きく下げてしまいます。

本当に何処でも実行出来るのか?

VBAを利用する理由のひとつに「Excelはどのパソコンにもインストールされており、どのパソコンでも利用できる」というのが有る。Microsoftはサブスクリプションモデルへの移行を目指しており、従来の買切り型ライセンスのOffice製品は2025年でサポートを終了することになっている。現在はデバイスライセンス下で複数の従業員が共有しているパソコンについても、2025年移行はユーザーライセンスに移行する事が求められる。例え利用時間が月に30分でも、アルバイトが20人いれば20ライセンスを購入することになるが、はたして購入し続けるだろうか?

また年々セキュリティ意識が高まっていく中、VBAを実行するためにセキュリティ設定を緩めて貰う事が、いつまで受け入れられるでしょうか?VBAを完全に禁止している会社も少なからずあるのが実情です。

またランタイムを追加で導入する必要が無く、何処でも実行可能であることがVBAを選択する理由なら、JavaScriptでもPythonでも良いはずです。

VBAを使い続ける上で必要なこと

VBAを使い続ける上で必要なことは、リスクを正しく認識する事だと考えて居ます。以下の様な問題があることを踏まえた上で、バランスを取りつつVBAと付き合っていく必要があるわけです。

  • VBAを使うためにセキュリティリスクを高めていること。
  • VBAの生産性を高めるような言語機能の拡張は20年ほど行われておらず、多言語と比較して生産性の低い開発言語となりつつあること。
  • VBAには将来に向けたロードマップが無く、今後もサポートが縮小していく可能性が高いこと。
  • セキュリティ問題、ソフトウェア資産管理上の問題から、VBAの利用を禁止している企業も少なくない。

少なくとも僕個人の方針として、今から積極的にVBAで書かれたソフトウェア資産を増やしたり、今からVBAを学ぶというのは、リスクに対してベネフィットが合わなくなる可能性が高いと捉えています。

VBAによるソフトウェア資産の総量を、VBAを止める必要が生じたときに速やかに他の開発言語に移植できる程度の量に納める必要があるでしょう。ソースコードの総量をメンテナンス可能な範囲に納める必要があるいのはVBAに限った話しではありませんが、VBAの場合には生産性の低さや将来性のなさから、より少ない量に抑える必要があるはずです。

マクロの実行を有効にする上で、セキュリティリスクを下げるため、ウィルス対策ソフトを使用するのは当然として、それ以外にもアクセス権管理やコンテンツフィルタなど、多層防御できる態勢を整えておく必要があるでしょう。新しいウィルスがウィルス対策ソフトのパターンファイルをすり抜ける事は珍しく無いのです。

ポート名を指定して既存のプリンタドライバを削除する

こちらのように”rundll32.exe printui.dll,PrintUIEntry ~”を使用すればコマンドラインからプリンタをインストールする事で設定の共通化を出来るが、既に同一ポート名でプリンタが導入されていた場合に複数のプリンタドライバをインストール出来てしまう。同一ポートを使用するプリンタドライバをインストールしてしまうと、設定⇒デバイス⇒プリンタとスキャナーで表示したときに、一つに集約されてしまい、非常に扱い難くなる。

そこで事前に以下のPowershellスクリプトでポート名を指定して既存プリンタを削除しておく事で、同一ポート名で重複登録することを防ぐとよい。

#RemovePrinterWithPort.ps1
$removePort = $args[0];
$printerNameKey = "プリンター名";
$portNameKey = "ポート名";

$printerName = "";
$portName = "";
cscript $env:SystemRoot\System32\Printing_Admin_Scripts\ja-JP\prnmngr.vbs -l | ForEach-Object {
    if ($_ -match ('^' + $printerNameKey + '.*'))
    {
        $printerName = $_.Replace(($printerNameKey + " "), "");
    }

    if ($_ -match ('^' + $portNameKey + '.*'))
    {
        $portName = $_.Replace(($portNameKey + " "), "");
        if ($portName -eq $removePort)
        {
            ("Remove Printer : " + $printerName);
            cscript $env:SystemRoot\System32\Printing_Admin_Scripts\ja-JP\prnmngr.vbs -d -p $printerName;
        }
    }
}

exit;

上記スクリプトをRemovePrinterWithPort.ps1で保存し、以下のコマンドでコマンドプロンプトから呼び出す。

 powershell.exe -Command .\RemovePrinterWithPort.ps1 IP_192.168.0.10

コマンドプロンプトからプリンタドライバをインストールする(Canon LIPS LX)

コマンドプロンプト(BATファイル)からサイレントにプリンタドライバをインストール手順です。コマンドプロンプトからインストール出来ると、キッティングやメンテナンスの手間を大幅に減らせます。CanonのLIPS LXドライバを例としていますが、他社のドライバでも本質的には同じです。

CanonのWEBサイトからダウンロードしたインストーラを起動し、展開されたファイルから.\x64\Driver下の以下のファイルを取り出します。

  • cnlb0m.cat
  • CNLB0MA64.INF
  • gpb0.cab

INFファイルの中味を確認する。以下の”Canon Generic Plus LIPSLX”がドライバ名にあたる。

; Canon Generic Plus LIPSLX printer INF for Microsoft Windows (x64)
; Copyright CANON INC. 2017
; CNLB0MA64.INF

[Version]
Signature="$Windows NT$"
Provider=%CANON%
ClassGUID={4D36E979-E325-11CE-BFC1-08002BE10318}
Class=Printer
DriverVer=06/26/2023,2.90.0.0
CatalogFile=CNLB0M.CAT

[Manufacturer]
"Canon" = Canon,NTamd64,NTamd64.6.0

;64-bit x64
[Canon.NTamd64]
"Canon Generic Plus LIPSLX"             = GPBDL,,1284_CID_CA_XPS_OIP
"Canon Generic Plus LIPSLX"             = GPBDL,,1284_CID_CA_UFRII_COLOR_OIP
"Canon Generic Plus LIPSLX"             = GPBDL,,1284_CID_CA_UFRII_BW_OIP
"Canon Generic Plus LIPSLX"             = GPBDL,CanonGeneric_V3_PrinC2DB

以下の様なバッチファイルを作成する。
1.prnmngr.vbsで既存プリンタ設定を列挙し既にインストール済みなら実行しない。
2.prnport.vbsでプリンタポートを作成
3.rundll32.exe printui.dll,PrintUIEntry~でドライバをインストールする。Canon以外のプリンタの場合には/fオプション以下のINFファイル名、/mオプション以下のプリンタドライバ名が変わる事になる。/bオプション以下は任意のプリンタ名となる。

set exe_dir=%~dp0

rem IPアドレス、ポート名を格納
set ip_addr=192.168.0.10
set ip_port=IP_192.168.0.10
set prname=iR-ADV C5850

rem ログ出力
set log_file=install.log
set driver_path=%exe_dir%

rem プリンタインストール済みかチェック
set prnmngr=C:\Windows\System32\Printing_Admin_Scripts\ja-JP\prnmngr.vbs
cscript %prnmngr% -l | findstr /l /C:"%prname%"
if %ERRORLEVEL%==0 GOTO END

:INSTALL
rem ポートの追加
set prnport=C:\Windows\System32\Printing_Admin_Scripts\ja-JP\prnport.vbs
cscript %prnport% -a -s %computername% -r %ip_port% -h %ip_addr% -o raw -n 9100 >> "%exe_dir%%log_file%

rem プリンタドライバの追加
rundll32.exe printui.dll,PrintUIEntry /if /f "%driver_path%\CNLB0MA64.INF" /v "Windows 10" /m "Canon Generic Plus LIPSLX" /r "%ip_port%" /b "%prname%"

:END

BIG-IP EDGE CLIENTが正常に動作しない

BIG-IP EDGE CLIENTが正常に動作しない場合、接続時にバックグラウンドで自動的にダウンロードするモジュールが壊れている場合があります。BIG-IP EDGE CLIENTは必要なファイルを”C:\Windows\Downloaded Program Files”にダウンロードしますので、管理者権限で当該フォルダの中にあるファイルを全て削除してから再実行してみてください。

当該フォルダはBIG-IP EDGE CLIENT以外のアプリケーションも使用している可能性があります。ですが仮に削除しても、実行時に再度ダウンロードするはずなので問題はありません。

SeleniumからChromeのインスタンス作成時にエラー

OpenQA.Selenium.WebDriverException: 'disconnected: Unable to receive message from renderer
  (failed to check if window was closed: disconnected: not connected to DevTools)
  (Session info: chrome=119.0.6045.124)'

C#環境でSeleniumからChromeのインスタンスを作成しようとすると上記のエラーが発生する。

この場合は下記の通り”–no-sandbox”オプションを追記すると問題が解決する場合がある。どうもコンソールリダイレクトのパイプライン処理などが引っかかる場合があるらしい。

using OpenQA.Selenium.Chrome;
using OpenQA.Selenium;
・・・
var options = new OpenQA.Selenium.Chrome.ChromeOptions();
options.AddArgument("--no-sandbox");
var newWebDriver = new ChromeDriver(options);

sandboxはWEB閲覧中のScript動作などの安全性を担保する上で重要な機能になる。接続先WEBサイトに不正なScriptが置かれていた場合、損失を受ける可能性もあるので注意が必要になる。Firefoxなど別のブラウザに移行した方が良いのかもしれない。

OpenTKとC#でOpenCLプログラミング

C#でお手軽にOpenCLを使ったプログラムを作れないかと思い、OpenTKを使用。

OpenTK 3.xではOpenCLの機能がClooとして独立したようですが、現行のOpenTK 4.xでは再びOpenCLが統合されています。

まずはNugetパッケージマネージャからOpenTK 4.7.xをプロジェクトに追加します。

サンプルプログラムはhttps://github.com/opentk/opentk/tree/master/tests/OpenToolkit.OpenCL.Testsにあるので参照。

using OpenTK.Compute.OpenCL;
using System.Text;
CL.GetPlatformIds(0, null, out uint platformCount);
CLPlatform[] platformIds = new CLPlatform[platformCount];
CL.GetPlatformIds(platformCount, platformIds, out _);
Console.WriteLine(platformIds.Length);
foreach (CLPlatform platform in platformIds)
{
    Console.WriteLine(platform.Handle);
    CL.GetPlatformInfo(platform, PlatformInfo.Name, out byte[] val);
    Console.WriteLine(System.Text.Encoding.ASCII.GetString(val));
}
foreach (IntPtr platformId in platformIds)
{
    CL.GetDeviceIds(new CLPlatform(platformId), DeviceType.All, out CLDevice[] deviceIds);
    CLContext context = CL.CreateContext(IntPtr.Zero, (uint)deviceIds.Length, deviceIds, IntPtr.Zero, IntPtr.Zero, out CLResultCode result);
    if (result != CLResultCode.Success)
    {
        throw new Exception("The context couldn't be created.");
    }
    string code = @"
                __kernel void add(__global float* A, __global float* B,__global float* result, const float mul)
                {
                    int i = get_global_id(0);
                    for (int j =0;j < 60000;j++)
                    {
                        for (int k =0;k < 60000;k++)
                        {
                            result[i] = (A[i] + B[i])*mul;
                        }
                    }
                }";
    CLProgram program = CL.CreateProgramWithSource(context, code, out result);
    CL.BuildProgram(program, (uint)deviceIds.Length, deviceIds, null, IntPtr.Zero, IntPtr.Zero);
    CLKernel kernel = CL.CreateKernel(program, "add", out result);
    int arraySize = 20;
    float[] A = new float[arraySize];
    float[] B = new float[arraySize];
    for (int i = 0; i < arraySize; i++)
    {
        A[i] = 1;
        B[i] = i;
    }
    CLBuffer bufferA = CL.CreateBuffer(context, MemoryFlags.ReadOnly | MemoryFlags.CopyHostPtr, A,
        out result);
    CLBuffer bufferB = CL.CreateBuffer(context, MemoryFlags.ReadOnly | MemoryFlags.CopyHostPtr, B,
        out result);
    float[] pattern = new float[] { 1, 3, 5, 7 };
    CLBuffer resultBuffer = new CLBuffer(CL.CreateBuffer(context, MemoryFlags.WriteOnly,
        new UIntPtr((uint)(arraySize * sizeof(float))), IntPtr.Zero, out result));
    try
    {
        CL.SetKernelArg(kernel, 0, bufferA);
        CL.SetKernelArg(kernel, 1, bufferB);
        CL.SetKernelArg(kernel, 2, resultBuffer);
        CL.SetKernelArg(kernel, 3, -1f);
        CLCommandQueue commandQueue = new CLCommandQueue(
                CL.CreateCommandQueueWithProperties(context, deviceIds[0], IntPtr.Zero, out result));
        CL.EnqueueFillBuffer(commandQueue, bufferB, pattern, UIntPtr.Zero, (UIntPtr)(arraySize * sizeof(float)), null,
            out _);
        //CL.EnqueueNDRangeKernel(commandQueue, kernel, 1, null, new UIntPtr[] {new UIntPtr((uint)A.Length)},
        //	null, 0, null,  out CLEvent eventHandle);
        CL.EnqueueNDRangeKernel(commandQueue, kernel, 1, null, new UIntPtr[] { new UIntPtr((uint)A.Length) },
            null, 0, null, out CLEvent eventHandle);
        CL.Finish(commandQueue);
        CL.SetEventCallback(eventHandle, (int)CommandExecutionStatus.Complete, (waitEvent, data) =>
        {
            float[] resultValues = new float[arraySize];
            CL.EnqueueReadBuffer(commandQueue, resultBuffer, true, UIntPtr.Zero, resultValues, null, out _);
            StringBuilder line = new StringBuilder();
            foreach (float res in resultValues)
            {
                line.Append(res);
                line.Append(", ");
            }
            Console.WriteLine(line.ToString());
        });
        //get rid of the buffers because we no longer need them
        CL.ReleaseMemoryObject(bufferA);
        CL.ReleaseMemoryObject(bufferB);
        CL.ReleaseMemoryObject(resultBuffer);
        //Release the program kernels and queues
        CL.ReleaseProgram(program);
        CL.ReleaseKernel(kernel);
        CL.ReleaseCommandQueue(commandQueue);
        CL.ReleaseContext(context);
        CL.ReleaseEvent(eventHandle);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
        throw;
    }
}

GPU上で実行されるプログラムはC言語で記述できます。

拍子抜けするぐらい簡単にOpenCLを使用したプログラムを作れるんですね。

どうしてもGPUへのデータ転送がボトルネックになりやすいので、高速化するのは中々難しいですが、機会があれば活用したいところ。

Docker上で実行しているNextCloudで”Updates between multiple major versions and downgrades are unsupported. Update failed.”が発生してアップデートに失敗する。

Dockerを使ってNextCloudを運用して居る。久しぶりにNextCloudバージョン画面を見たところ、「保守終了したバージョン」との警告が。あわててアップデートを行ったところ、ずっとメンテナンスモードから戻らなくなってしまった。そう、うっかりとversion 23→version 25にアップデートを掛けてしまったため、処理が正常に終了せずに環境が壊れてしまったのだ。

以下のコマンドを実行してメンテナンスモードを強制的に解除してNextCloudをWERBで開くがUpgradeの確認画面になり、そしてUpgradeは失敗してしまう。

$ sudo docker exec -u www-data <container name> php occ maintenance:mode --off

以下のコマンドを実行してコマンドラインからUpgradeを実施するが、「Updates between multiple major versions and downgrades are unsupported. Update failed.」のエラーになってしまう。

$ sudo docker exec -u www-data <container name> php occ upgrade

リカバリ方法がないかと探していたところ「How to fix an accidental Nextcloud docker image update」にたどり着いたので、こちらの方法でリカバリを試みることにする。

まずhtml/config/config.phpを開き、正確なバージョンを確認する。ここでは「’version’ => ‘23.0.0.10’,」とあるとおり、23.0.0.10が正確なージョンになる。

  'datadirectory' => '/var/www/html/data',
  'dbtype' => 'mysql',
  'version' => '23.0.0.10',
  'overwrite.cli.url' => 'https://example.net',
  'dbname' => 'nextcloud',

次にhtml/version.phpを編集する。既にversion 25のファイルに置き換わってしまっているため、これを書き換えて23→24へのアップグレードを通すために、$OC_Versionをarray(25,0,2,3)からarray(23,0,0,10)に、$OC_VersionStringを’25.0.2’から’23.0.0’に、array (‘24.0’ => true, ‘25.0’ => true,)をarray (‘23.0’ => true, ‘24.0’ => true,)に、下記の通りに書き換えます。

<?php
$OC_Version = array(23,0,0,10);
$OC_VersionString = '23.0.0';
$OC_Edition = '';
$OC_Channel = 'stable';
$OC_VersionCanBeUpgradedFrom = array (
  'nextcloud' =>
  array (
    '23.0' => true,
    '24.0' => true,
  ),
  'owncloud' =>
  array (
    '10.11' => true,
  ),
);
$OC_Build = '2022-12-08T11:32:17+00:00 9c791972de9c2561a9b36c1a60e48c25315ecca5';
$vendor = 'nextcloud';

続いてdocker-compose.ymlを編集します。下記のようにnextcloud:24のようにアップデート先となる旧バージョンのdockerイメージを指定します。

  nextcloud:
    image: nextcloud:24

これで23→24にアップデートする環境が整うので、以下のコマンドを実行してNextCloudを起動し、23から24へのアップデートを実行します。

$ sudo docker-compose up --build -d
$ sudo docker exec -u www-data <container name> php occ upgrade

version 24へのアップデートが正常に終了したら、再びdocker-compose.ymlを編集して元に戻します。その後に再び下記のコマンドを実行すれば、24から25へのバージョンアップを行えます。

$ sudo docker-compose up --build -d
$ sudo docker exec -u www-data <container name> php occ upgrade

MNPで携帯電話を乗っ取りSMS認証を突破される

さっきまで使えてたスマホ、通話音が…しない 勝手に解約されたかも 被害男性の証言

偽造運転免許証をもちいて携帯電話のMNPを申込みんで携帯電話を乗っ取り、オンラインバンクのSMS認証を突破されてしまうという問題が多数発生しているらしい。記事の中でも「パスワードを使い回さないなど、やはり個人の対策が重要だ」と書かれているとおり、一番の問題はパスワードを適切に管理出来て居なかった事にある。

SMSを使用した多要素認証は、NIST(米国立標準技術研究所)でも条件付き推奨としている。推奨するための条件は、「他の認証方式と併用すること」「代替の認証方法を用意すること」「危険性の評価し公表すること」三つだ。SMSは電話会社での管理が適切である事を前提としており、技術的あるいは社会的方法で容易に突破されうる事が分かっているからだ。

SMSは攻撃に弱い認証方法であるという前提を理解して、正しくパスワードによる認証を使う事が大事です。「サービス毎に異なるパスワードを使う」「パスワードはランダムな文字列にする」「前述二つを実施するのはパスワード管理ツール無しでは無理なので、適当なツールを利用する」の三点をしっかりまもろう。

そしてエンジニアもSMS認証は弱いと言う事をちゃんと認識してサービスを設計しよう。