2020年9月30日 星期三

[研究] HTTPS 支援加密演算法最大長度金鑰測試

[研究] HTTPS 支援加密演算法最大長度金鑰測試

2020-09-30

考慮幾個因素

Q1.Web Server 是否支援?(IIS, Apache httpd , Tomcat)

Q2.掃描工具是否支援?

********************************************************************************

nmap 7.80 版是目前最新版

https://nmap.org/

受測環境:Windows Server 2019 Standard + IIS (已經關閉不安全的設定,並且經過 WAF )


Starting Nmap 7.80 ( https://nmap.org )

Host is up (0.00s latency).


PORT    STATE SERVICE
443/tcp open  https
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| ssl-enum-ciphers:
|   TLSv1.1:
|     ciphers:
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
|     compressors:
|       NULL
|     cipher preference: server
|     warnings:
|       Key exchange (dh 1024) of lower strength than certificate key
|   TLSv1.2:
|     ciphers:
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 1024) - A
|     compressors:
|       NULL
|     cipher preference: server
|     warnings:
|       Key exchange (dh 1024) of lower strength than certificate key
|_  least strength: A


Nmap done: 1 IP address (1 host up) scanned in 2.02 seconds



********************************************************************************

SSL Labs

https://www.ssllabs.com/ssltest/analyze.html?d=xxx.xxx.xxx.tw


Protocols
TLS 1.3     No
TLS 1.2     Yes
TLS 1.1     Yes
TLS 1.0     No
SSL 3        No
SSL 2        No


Cipher Suites
# TLS 1.2 (suites in server-preferred order)
TLS_RSA_WITH_AES_256_CBC_SHA (0x35)   WEAK   256
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f)   WEAK    128
TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d)   WEAK     256
TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c)   WEAK     128
TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c)   WEAK    128
TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d)   WEAK   256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)   ECDH secp192r1 (eq. 1536 bits RSA)   FS   WEAK        128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)   ECDH secp192r1 (eq. 1536 bits RSA)   FS   WEAK        256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)   ECDH secp192r1 (eq. 1536 bits RSA)   FS  128
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)   ECDH secp192r1 (eq. 1536 bits RSA)   FS 256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39)   DH 1024 bits   FS   WEAK      256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33)   DH 1024 bits   FS   WEAK      128
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x6b)   DH 1024 bits   FS   WEAK        256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67)   DH 1024 bits   FS   WEAK        128
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e)   DH 1024 bits   FS   WEAK      128
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9f)   DH 1024 bits   FS   WEAK       256
# TLS 1.1 (suites in server-preferred order)
TLS_RSA_WITH_AES_256_CBC_SHA (0x35)   WEAK 256
TLS_RSA_WITH_AES_128_CBC_SHA (0x2f)   WEAK 128
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)   ECDH secp192r1 (eq. 1536 bits RSA)   FS   WEAK 128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)   ECDH secp192r1 (eq. 1536 bits RSA)   FS   WEAK 256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39)   DH 1024 bits   FS   WEAK 256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33)   DH 1024 bits   FS   WEAK 128


Handshake Simulation
Android 4.4.2  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Android 5.0.0  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Android 6.0     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Android 7.0     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Android 8.0     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Android 8.1     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Android 9.0     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
BingPreview Jan 2015     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Chrome 49 / XP SP3        RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Chrome 69 / Win 7  R   RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Chrome 70 / Win 10       RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Chrome 80 / Win 10  R RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Firefox 31.3.0 ESR / Win 7      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Firefox 47 / Win 7  R     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Firefox 49 / XP SP3  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Firefox 62 / Win 7  R     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Firefox 73 / Win 10  R   RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Googlebot Feb 2018       RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
IE 11 / Win 7  R     RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
IE 11 / Win 8.1  R  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
IE 11 / Win Phone 8.1  R       RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
IE 11 / Win Phone 8.1 Update  R  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
IE 11 / Win 10  R   RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Edge 15 / Win 10  R      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Edge 16 / Win 10  R      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Edge 18 / Win 10  R      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Edge 13 / Win Phone 10  R   RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Java 8u161      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Java 11.0.3      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Java 12.0.1      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
OpenSSL 1.0.1l  R  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
OpenSSL 1.0.2s  R RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
OpenSSL 1.1.0k  R RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
OpenSSL 1.1.1c  R RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 6 / iOS 6.0.1  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 7 / iOS 7.1  R       RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 7 / OS X 10.9  R   RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 8 / iOS 8.4  R       RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 8 / OS X 10.10  R RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 9 / iOS 9  R  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 9 / OS X 10.11  R RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 10 / iOS 10  R      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 10 / OS X 10.12  R       RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 12.1.2 / MacOS 10.14.6 Beta  R RSA 2048 (SHA256)       TLS 1.2        TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Safari 12.1.1 / iOS 12.3.1  R  RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
Apple ATS 9 / iOS 9  R   RSA 2048 (SHA256)       TLS 1.2     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA   ECDH secp256r1  FS
Yahoo Slurp Jan 2015      RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS
YandexBot Jan 2015        RSA 2048 (SHA256)       TLS 1.2     TLS_RSA_WITH_AES_256_CBC_SHA  No FS


********************************************************************************

結果:

(Windows Server 2019 + IIS ) + ( nmap 7.80 或 SSLLabs ) 支援金鑰的最大長度

支援 AES_256

支援 SHA384,沒有 SHA512

支援 rsa 2048,沒有 rsa 4096

(完)

相關 

進階加密標準(英語:Advanced Encryption Standard,縮寫:AES) - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86

SHA家族 - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/SHA%E5%AE%B6%E6%97%8F

RSA加密演算法 - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95

 

[研究] 使用者 'xxx' 的 卸除 失敗。 (Microsoft.SqlServer.Smo)資料庫主體在資料庫中擁有結構描述且無法卸除。

[研究] 使用者 'xxx' 的 卸除 失敗。  (Microsoft.SqlServer.Smo)資料庫主體在資料庫中擁有 結構描述 且無法卸除。

2020-09-30

標題: Microsoft SQL Server Management Studio

------------------------------

使用者 'xxx' 的 卸除 失敗。  (Microsoft.SqlServer.Smo)

如需說明,請按一下: https://go.microsoft.com/fwlink?ProdName=Microsoft+SQL+Server&ProdVer=16.100.41011.9+(SqlManagementObjects-master-APPLOCAL)&EvtSrc=Microsoft.SqlServer.Management.Smo.ExceptionTemplates.FailedOperationExceptionText&EvtID=卸除+User&LinkId=20476

實際上該網頁內容已經不存在了。

------------------------------

其他資訊:

執行 Transact-SQL 陳述式或批次時發生例外狀況。 (Microsoft.SqlServer.ConnectionInfo)

------------------------------

資料庫主體在資料庫中擁有 結構描述 且無法卸除。 (Microsoft SQL Server, 錯誤: 15138)

如需說明,請按一下: http://go.microsoft.com/fwlink?ProdName=Microsoft%20SQL%20Server&ProdVer=15.00.2000&EvtSrc=MSSQLServer&EvtID=15138&LinkId=20476

實際上該網頁內容已經不存在了。

********************************************************************************

問題:使用者帳號刪除失敗





********************************************************************************
解決:【結構描述擁有者】換成和【結構描述名稱】相同的。

db_accessadmin、db_ddladmin 和 db_owner 也相同處理。










解決了。

(完)

[研究]Android 手機釋出空間

[研究]Android 手機釋出空間

2020-09-30

釋出空間 - Android說明

https://support.google.com/android/answer/7431795

********************************************************************************

LINE 清除紀錄

首先,點開手機中的LINE 通訊軟體,按左下角「主頁」,按下右上角的「設定圖示」(六角齒輪),點選「聊天」,有個「記錄」選項,可以刪除非必要資料。 




(下圖) 建議先刪除檔案,不夠再刪除記錄



********************************************************************************

清除快取 Cache







同理,可以清除其他應用程式快取。

********************************************************************************

清除Chrome瀏覽資料

清除瀏覽資料 - Android 裝置 - Google Chrome說明

https://support.google.com/chrome/answer/2392709?co=GENIE.Platform%3DAndroid&hl=zh-Hant







********************************************************************************

清理「訊息」應用程式中的對話

https://support.google.com/messages/answer/7028817?hl=zh-Hant

********************************************************************************

如何從Messenger(Android)刪除所有聊天

不支援,只能一篇篇刪除。

********************************************************************************

(完)

2020年9月29日 星期二

[研究]Ionic.Zip 1.9.1.8 即將淘汰,替代套件 DotNetZip >= 1.9.1.8

[研究]Ionic.Zip 1.9.1.8 即將淘汰,替代套件 DotNetZip >= 1.9.1.8

2020-09-29



Ionic Zip Library v1.9.1.6
DotNetZip

NuGet Gallery | Ionic.Zip 1.9.1.8
最後更新 2017/11/22

********************************************************************************
DotNetZip 

https://archive.codeplex.com/?p=dotnetzip

DotNetZip.zip 下載解壓,其中 sourceCode.zip 為2018-01-08建立。


NuGet Gallery | DotNetZip 1.13.8

https://www.nuget.org/packages/DotNetZip/

https://github.com/haf/DotNetZip.Semverd

最後更新2020-05-22

********************************************************************************

[研究][C#][ASP.NET][WebForm] 使用 Ionic.Zip 匯出、匯出 ODF/.ods 檔案

http://shaurong.blogspot.com/2020/09/caspnetwebform-ioniczip-odfods.html

實際測試,NuGet 把 Ionic.Zip 1.9.1.8移除,安裝 DotNetZip 1.13.8,程式仍可正常使用。


using Ionic.Zip;    
// Ionic.Zip 被 DotNetZip 取代,NuGet 安裝 DotNetZip,但是 using 還是用舊名稱 Ionic.Zip 

(完)

[研究][C#]用OdsReaderWrite匯出(寫入)、匯入(讀取) ODF/.ods 檔案 (使用 Ionic.Zip、DotNetZip)

[研究][C#]用OdsReaderWrite匯出(寫入)、匯入(讀取) ODF/.ods 檔案 (使用 Ionic.Zip、DotNetZip)

2020-09-29
2020-12-15 更新
2021-01-03 更新

ODF release dates:

  • ODF 1.0 May 2005
  • ODF 1.1 February 2007
  • ODF 1.2 September 2012
  • ODF 1.3 January 2020

https://wiki.documentfoundation.org/Comparison_of_ODF_software

How to Read and Write ODF/ODS Files (OpenDocument Spreadsheets)
28 Jul 2011
https://www.codeproject.com/Articles/38425/How-to-Read-and-Write-ODF-ODS-Files-OpenDocument-2
所以 odsreadwrite.zip 可能只支援到 ODF, ODS 1.1 版


Visual Studio 2019 v15.6.0

OdsReaderWriter.cs 和 template.ods 取自上面網站

template.ods 放到 bin 目錄。

NuGet 要安裝 Ionic.Zip 套件。(Ionic.Zip 已經淘汰,請改用DotNetZip)

Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ODSExport.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
        </div>
    </form>
</body>
</html>


Default.aspx.cs
using OdsReadWriteNameSpace;    // 要 using  namespace ,才能存取到 OdsReadWriter 這個 class,不是直接  using 這個 OdsReadWriter Class
using System;
using System.Data;
using System.Web.UI.WebControls;

namespace ODSExport
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            DataSet ds = new DataSet("DS1");
            //DataTable dt = new DataTable();
            DataTable dt = ds.Tables.Add("DS1DT");

            DataColumn fNameColumn = new DataColumn();
            fNameColumn.DataType = System.Type.GetType("System.String");
            fNameColumn.ColumnName = "Fname";
            fNameColumn.DefaultValue = "Fname";
            dt.Columns.Add(fNameColumn);

            DataColumn lNameColumn = new DataColumn();
            lNameColumn.DataType = System.Type.GetType("System.String");
            lNameColumn.ColumnName = "Lname";
            lNameColumn.DefaultValue = "Lname";
            dt.Columns.Add(lNameColumn);

            DataRow dr = dt.NewRow();
            dr["Fname"] = "tt0";
            dr["Lname"] = "tt1";
            dt.Rows.Add(dr);

            DataRow dr2 = dt.NewRow();
            dr2["Fname"] = "aa1";
            dr2["Lname"] = "aa2";
            dt.Rows.Add(dr2);

            OdsReaderWriter odsFile = new OdsReaderWriter();
            odsFile.WriteOdsFile(ds, @"C:\TEMP\1.ods");
        }
    }
}

OdsReaderWriter.cs

using System;
using System.Data;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Xml;
using Ionic.Zip;

namespace OdsReadWriteNameSpace
{
    internal sealed class OdsReaderWriter
    {
        // Namespaces. We need this to initialize XmlNamespaceManager so that we can search XmlDocument.
        private static string[,] namespaces = new string[,]
        {
            {"table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0"},
            {"office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0"},
            {"style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0"},
            {"text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0"},           
            {"draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"},
            {"fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"},
            {"dc", "http://purl.org/dc/elements/1.1/"},
            {"meta", "urn:oasis:names:tc:opendocument:xmlns:meta:1.0"},
            {"number", "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"},
            {"presentation", "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"},
            {"svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"},
            {"chart", "urn:oasis:names:tc:opendocument:xmlns:chart:1.0"},
            {"dr3d", "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"},
            {"math", "http://www.w3.org/1998/Math/MathML"},
            {"form", "urn:oasis:names:tc:opendocument:xmlns:form:1.0"},
            {"script", "urn:oasis:names:tc:opendocument:xmlns:script:1.0"},
            {"ooo", "http://openoffice.org/2004/office"},
            {"ooow", "http://openoffice.org/2004/writer"},
            {"oooc", "http://openoffice.org/2004/calc"},
            {"dom", "http://www.w3.org/2001/xml-events"},
            {"xforms", "http://www.w3.org/2002/xforms"},
            {"xsd", "http://www.w3.org/2001/XMLSchema"},
            {"xsi", "http://www.w3.org/2001/XMLSchema-instance"},
            {"rpt", "http://openoffice.org/2005/report"},
            {"of", "urn:oasis:names:tc:opendocument:xmlns:of:1.2"},
            {"rdfa", "http://docs.oasis-open.org/opendocument/meta/rdfa#"},
            {"config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0"}
        };

        // Read zip stream (.ods file is zip file).
        private ZipFile GetZipFile(Stream stream)
        {
            return ZipFile.Read(stream);
        }

        // Read zip file (.ods file is zip file).
        private ZipFile GetZipFile(string inputFilePath)
        {
            return ZipFile.Read(inputFilePath);
        }

        private XmlDocument GetContentXmlFile(ZipFile zipFile)
        {
            // Get file(in zip archive) that contains data ("content.xml").
            ZipEntry contentZipEntry = zipFile["content.xml"];

            // Extract that file to MemoryStream.
            Stream contentStream = new MemoryStream();
            contentZipEntry.Extract(contentStream);
            contentStream.Seek(0, SeekOrigin.Begin);

            // Create XmlDocument from MemoryStream (MemoryStream contains content.xml).
            XmlDocument contentXml = new XmlDocument();
            contentXml.Load(contentStream);

            return contentXml;
        }

        private XmlNamespaceManager InitializeXmlNamespaceManager(XmlDocument xmlDocument)
        {
            XmlNamespaceManager nmsManager = new XmlNamespaceManager(xmlDocument.NameTable);

            for (int i = 0; i < namespaces.GetLength(0); i++)
                nmsManager.AddNamespace(namespaces[i, 0], namespaces[i, 1]);

            return nmsManager;
        }

        /// <summary>
        /// Read .ods file and store it in DataSet.
        /// </summary>
        /// <param name="inputFilePath">Path to the .ods file.</param>
        /// <returns>DataSet that represents .ods file.</returns>
        public DataSet ReadOdsFile(string inputFilePath)
        {
            ZipFile odsZipFile = this.GetZipFile(inputFilePath);

            // Get content.xml file
            XmlDocument contentXml = this.GetContentXmlFile(odsZipFile);

            // Initialize XmlNamespaceManager
            XmlNamespaceManager nmsManager = this.InitializeXmlNamespaceManager(contentXml);

            DataSet odsFile = new DataSet(Path.GetFileName(inputFilePath));

            foreach (XmlNode tableNode in this.GetTableNodes(contentXml, nmsManager))
                odsFile.Tables.Add(this.GetSheet(tableNode, nmsManager));

            return odsFile;
        }

        // In ODF sheet is stored in table:table node
        private XmlNodeList GetTableNodes(XmlDocument contentXmlDocument, XmlNamespaceManager nmsManager)
        {
            return contentXmlDocument.SelectNodes("/office:document-content/office:body/office:spreadsheet/table:table", nmsManager);
        }

        private DataTable GetSheet(XmlNode tableNode, XmlNamespaceManager nmsManager)
        {
            DataTable sheet = new DataTable(tableNode.Attributes["table:name"].Value);

            XmlNodeList rowNodes = tableNode.SelectNodes("table:table-row", nmsManager);

            int rowIndex = 0;
            foreach (XmlNode rowNode in rowNodes)
                this.GetRow(rowNode, sheet, nmsManager, ref rowIndex);

            return sheet;
        }

        private void GetRow(XmlNode rowNode, DataTable sheet, XmlNamespaceManager nmsManager, ref int rowIndex)
        {
            XmlAttribute rowsRepeated = rowNode.Attributes["table:number-rows-repeated"];
            if (rowsRepeated == null || Convert.ToInt32(rowsRepeated.Value, CultureInfo.InvariantCulture) == 1)
            {
                while (sheet.Rows.Count < rowIndex)
                    sheet.Rows.Add(sheet.NewRow());

                DataRow row = sheet.NewRow();

                XmlNodeList cellNodes = rowNode.SelectNodes("table:table-cell", nmsManager);

                int cellIndex = 0;
                foreach (XmlNode cellNode in cellNodes)
                    this.GetCell(cellNode, row, nmsManager, ref cellIndex);

                sheet.Rows.Add(row);

                rowIndex++;
            }
            else
            {
                rowIndex += Convert.ToInt32(rowsRepeated.Value, CultureInfo.InvariantCulture);
            }

            // sheet must have at least one cell
            if (sheet.Rows.Count == 0)
            {
                sheet.Rows.Add(sheet.NewRow());
                sheet.Columns.Add();
            }
        }

        private void GetCell(XmlNode cellNode, DataRow row, XmlNamespaceManager nmsManager, ref int cellIndex)
        {
            XmlAttribute cellRepeated = cellNode.Attributes["table:number-columns-repeated"];

            if (cellRepeated == null)
            {
                DataTable sheet = row.Table;

                while (sheet.Columns.Count <= cellIndex)
                    sheet.Columns.Add();

                row[cellIndex] = this.ReadCellValue(cellNode);

                cellIndex++;
            }
            else
            {
                cellIndex += Convert.ToInt32(cellRepeated.Value, CultureInfo.InvariantCulture);
            }
        }

        private string ReadCellValue(XmlNode cell)
        {
            XmlAttribute cellVal = cell.Attributes["office:value"];

            if (cellVal == null)
                return String.IsNullOrEmpty(cell.InnerText) ? null : cell.InnerText;
            else
                return cellVal.Value;
        }

        /// <summary>
        /// Writes DataSet as .ods file.
        /// </summary>
        /// <param name="odsFile">DataSet that represent .ods file.</param>
        /// <param name="outputFilePath">The name of the file to save to.</param>
        public void WriteOdsFile(DataSet odsFile, string outputFilePath)
        {

            //ZipFile templateFile = this.GetZipFile(Assembly.GetExecutingAssembly().GetManifestResourceStream("OdsReadWrite.template.ods"));
            //ZipFile templateFile = this.GetZipFile(File.OpenRead(@"C:\CODE\ODSExport\ODSExport\bin\template.ods"));
            //ZipFile templateFile = this.GetZipFile(File.OpenRead(Server.MapPath("/") + "template.ods");

            ZipFile templateFile = this.GetZipFile(File.OpenRead(HttpContext.Current.Server.MapPath("/template.ods"))); 

            XmlDocument contentXml = this.GetContentXmlFile(templateFile);

            XmlNamespaceManager nmsManager = this.InitializeXmlNamespaceManager(contentXml);

            XmlNode sheetsRootNode = this.GetSheetsRootNodeAndRemoveChildrens(contentXml, nmsManager);

            foreach (DataTable sheet in odsFile.Tables)
                this.SaveSheet(sheet, sheetsRootNode);

            this.SaveContentXml(templateFile, contentXml);

            templateFile.Save(outputFilePath);
        }

        private XmlNode GetSheetsRootNodeAndRemoveChildrens(XmlDocument contentXml, XmlNamespaceManager nmsManager)
        {
            XmlNodeList tableNodes = this.GetTableNodes(contentXml, nmsManager);

            XmlNode sheetsRootNode = tableNodes.Item(0).ParentNode;
            // remove sheets from template file
            foreach (XmlNode tableNode in tableNodes)
                sheetsRootNode.RemoveChild(tableNode);

            return sheetsRootNode;
        }

        private void SaveSheet(DataTable sheet, XmlNode sheetsRootNode)
        {
            XmlDocument ownerDocument = sheetsRootNode.OwnerDocument;

            XmlNode sheetNode = ownerDocument.CreateElement("table:table", this.GetNamespaceUri("table"));

            XmlAttribute sheetName = ownerDocument.CreateAttribute("table:name", this.GetNamespaceUri("table"));
            sheetName.Value = sheet.TableName;
            sheetNode.Attributes.Append(sheetName);

            this.SaveColumnDefinition(sheet, sheetNode, ownerDocument);

            this.SaveRows(sheet, sheetNode, ownerDocument);

            sheetsRootNode.AppendChild(sheetNode);
        }

        private void SaveColumnDefinition(DataTable sheet, XmlNode sheetNode, XmlDocument ownerDocument)
        {
            XmlNode columnDefinition = ownerDocument.CreateElement("table:table-column", this.GetNamespaceUri("table"));

            XmlAttribute columnsCount = ownerDocument.CreateAttribute("table:number-columns-repeated", this.GetNamespaceUri("table"));
            columnsCount.Value = sheet.Columns.Count.ToString(CultureInfo.InvariantCulture);
            columnDefinition.Attributes.Append(columnsCount);

            sheetNode.AppendChild(columnDefinition);
        }

        private void SaveRows(DataTable sheet, XmlNode sheetNode, XmlDocument ownerDocument)
        {
            DataRowCollection rows = sheet.Rows;
            for (int i = 0; i < rows.Count; i++)
            {
                XmlNode rowNode = ownerDocument.CreateElement("table:table-row", this.GetNamespaceUri("table"));

                this.SaveCell(rows[i], rowNode, ownerDocument);

                sheetNode.AppendChild(rowNode);
            }
        }

        private void SaveCell(DataRow row, XmlNode rowNode, XmlDocument ownerDocument)
        {
            object[] cells = row.ItemArray;

            for (int i = 0; i < cells.Length; i++)
            {
                XmlElement cellNode = ownerDocument.CreateElement("table:table-cell", this.GetNamespaceUri("table"));

                if (row[i] != DBNull.Value)
                {
                    // We save values as text (string)
                    XmlAttribute valueType = ownerDocument.CreateAttribute("office:value-type", this.GetNamespaceUri("office"));
                    valueType.Value = "string";
                    cellNode.Attributes.Append(valueType);

                    XmlElement cellValue = ownerDocument.CreateElement("text:p", this.GetNamespaceUri("text"));
                    cellValue.InnerText = row[i].ToString();
                    cellNode.AppendChild(cellValue);
                }

                rowNode.AppendChild(cellNode);
            }
        }

        private void SaveContentXml(ZipFile templateFile, XmlDocument contentXml)
        {
            templateFile.RemoveEntry("content.xml");

            MemoryStream memStream = new MemoryStream();
            contentXml.Save(memStream);
            memStream.Seek(0, SeekOrigin.Begin);

            templateFile.AddEntry("content.xml", memStream);
        }

        private string GetNamespaceUri(string prefix)
        {
            for (int i = 0; i < namespaces.GetLength(0); i++)
            {
                if (namespaces[i, 0] == prefix)
                    return namespaces[i, 1];
            }

            throw new InvalidOperationException("Can't find that namespace URI");
        }
    }
}


********************************************************************************

如果產生的 .ods 檔案無法用 Excel 開啟,而出現:

這個活頁簿無法由 Microsoft Excel 開啟或修復,因其已損毀。



可能是資料包含 .ods 檔案無法允許的字元 (一般是不可見字元),但是該字元在 C# 的 string 變數和 SQL Server 的 nvarchar 欄位是允許使用的。最好 String.Replace( originString, ""); 把特殊字元移除。


********************************************************************************

[研究]Ionic.Zip 1.9.1.8 即將淘汰,替代套件 DotNetZip >= 1.9.1.8

實際測試,NuGet 把 Ionic.Zip 1.9.1.8移除,安裝 DotNetZip 1.13.8,程式仍可正常使用。


using Ionic.Zip;    
// Ionic.Zip 被 DotNetZip 取代,NuGet 安裝 DotNetZip,但是 using 還是用舊名稱 Ionic.Zip 

********************************************************************************


注意,此測試寫入 C:\temp 目錄,如果在 Visual Studio 中執行,因為你是 administrator 或 administrators 群組中人,故有權寫入;如果程式用於 IIS 網站,此目錄必須開放讓 IIS_IUSRS 使用者有寫入權限。

(完)

相關

[研究][ASP.NET]使用 OdsReaderWriter + DotNetZip 1.15.0 (Ionic.Zip) 匯出寫入 .ods

2020年9月23日 星期三

[研究] sshd 安裝架設 (CentOS 8.2)

[研究] sshd 安裝架設 (CentOS 8.2)

2020-09-23

sshd = Secure Shell (SSH) Daemon Service

顯示作業系統版本

$ cat /etc/redhat-release

CentOS Linux release 8.2.2004


********************************************************************************

安裝 ssh daemon service

$ sudo yum -y install openssh-server

$ sudo dnf -y install openssh-server


********************************************************************************

顯示狀態

$ sudo systemctl status sshd

立刻啟動、停用、重新啟動

$ sudo systemctl start sshd

$ sudo systemctl stop sshd

$ sudo systemctl restart sshd




********************************************************************************

設定開啟動是否自動啟用 sshd

$ sudo systemctl enable sshd

$ sudo systemctl disable sshd




********************************************************************************

防火牆開放 port 22

$ sudo yum install firewalld

$ sudo systemctl enable firewalld

$ sudo firewall-cmd --zone=public --permanent --add-service=ssh

$ sudo firewall-cmd --reload


檢查狀態
$ sudo firewall-cmd --state
$ firewall-cmd --get-active-zones
$ sudo firewall-cmd --list-all

********************************************************************************

設定檔案

/etc/ssh/sshd_config 

若修改,要重新啟動 sshd

$ sudo systemctl reload sshd

(完)

相關

firewalld

https://firewalld.org/documentation/man-pages/firewall-cmd.html

https://firewalld.org/documentation/utilities/firewall-cmd.html



2020年9月21日 星期一

[研究] 查詢 Windows Update 的 hotfix 更新的取代和被取代(被更新)狀態

[研究] 查詢 Windows Update 的 hotfix 更新的取代和被取代(被更新)狀態

2020-09-21

Microsoft Update Catalog

https://www.catalog.update.microsoft.com/Home.aspx

Ex: 輸入 "Windows Server 2019"

Ex: 輸入 KB4562562


查特定KB資訊方法,例如:KB4557222

https://support.microsoft.com/help/4557222

Click 圖片可以看 100% 原始尺寸




********************************************************************************
查Windows Update更新過哪些 KB







(完)

[研究][JavaScript] SweetAlert 與 SweetAlert2

[研究][JavaScript] SweetAlert 與 SweetAlert2

2020-09-21

SweetAlert 和 SweetAlert2 是 JavaScript 前端套件。

********************************************************************************

SweetAlert

Tristan Edwards (特里斯坦·愛德華茲)

NuGet 安裝時,你會發現一堆類似的稱呼。
不要選第一個 SweetAlert (版本 v1.0.0),
第一個 SweetAlert 的專案目錄其實是
https://github.com/lipis/bootstrap-sweetalert
它是 SweetAlert for Bootstrap

選第二個 SweetAlert.Base (版本 v1.1.3)才是,注意專案 URL 是

https://t4t5.github.com/sweetalert

https://github.com/t4t5/sweetalert

SweetAlert 最後是 14 Dec 2017 釋出的 v2.1.0 版,但是 NuGet 沒有提供這版。
https://github.com/t4t5/sweetalert/releases

官方網站
https://sweetalert.js.org/

SweetAlert.Base 最新 1.1.3 版,最後更新 2015/10/21,已經快5年沒更新了。 
https://www.nuget.org/packages/SweetAlert.Base/

Announcing SweetAlert 2.0
Tristan Edwards  Sep 7, 2017
https://medium.com/@edwards/announcing-sweetalert-2-0-eebd2f66bac2

Tristan Edwards 提到 2014 年建立 SweetAlert,並提到 SweetAlert2,請大家關注 https://sweetalert.js.org/ 網站。
但是網站尚未提到推出 SweetAlert2,也沒提到 limonte 此人。

********************************************************************************

SweetAlert2

目前最新版 v10.3.0,官方網站
https://sweetalert2.github.io/
作者 limonte (Limon Monte,利蒙·蒙特),和 SweetAlert 作者不同。

官方網站;
https://sweetalert2.github.io/

SweetAlert2 各版本,持續更新中,最新 10.3.0 (2020-09-20) 版
https://github.com/sweetalert2/sweetalert2/releases

sweetalert2 CDN Files
https://www.jsdelivr.com/package/npm/sweetalert2

Become a sponsor to limonte
https://github.com/sponsors/limonte
4 years ago I forked SweetAlert and since then SweetAlert2 became twice more popular than the original plugin:
作者 limonte 說 SweetAlert2 是 fork 作者 Tristan Edwards 的 SweetAlert 專案。

Git - 參與一個專案 (Fork 專案)

https://git-scm.com/book/zh-tw/v2/GitHub-%E5%8F%83%E8%88%87%E4%B8%80%E5%80%8B%E5%B0%88%E6%A1%88

SweetAlert2 沒有 NuGet 安裝的方法。

********************************************************************************

敝人沒有詳細研究比較把 SweetAlert 換成 SweetAlert2 後,是否所有 code 都仍能使用。 

(完)

2020年9月18日 星期五

[研究][ASP.NET][WebForm] RichTextEditor 8.0.1 WYSIWYG HTML Editor 試用 (付費)

[研究][ASP.NET][WebForm] RichTextEditor 8.0.1 WYSIWYG HTML Editor 試用 (付費)

2020-09-17

WYSIWYG HTML Editor = 所見即所得 HTML 網頁編輯器

WYSIWYG = What You See Is What You Get 

官方網站
https://richtexteditor.com/

定價
https://richtexteditor.com/pricing.aspx

社群版:會有 "Powered by" 文字
What are the limitations of the community version?
All features work the same as they do in the full version. The community version allows you run editor on one domain and it has "Powered by" text in the footer.

Rich Text Editor 範例
https://richtexteditor.com/demos/default.aspx















NuGet 版沒 License 不能用。

********************************************************************************
偶然發現官方網站版本 1.012 和 NuGet 版本 8.2.0.9 差異很大,可能大改版重新給版號。下載用看看

官方網站






********************************************************************************
自己寫個程式試試


Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="RTETest.Default" %>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />
	<script type="text/javascript" src="/richtexteditor/rte.js"></script>
	<script type="text/javascript" src='/richtexteditor/plugins/all_plugins.js'></script>
</head>
<body>
    <form id="form1" runat="server">
        <input name="htmlcode" id="inp_htmlcode" type="hidden" />
        <div id="div_editor1" class="richtexteditor" style="width: 960px; margin: 0 auto;"></div>       
        <script>
            var editor1 = new RichTextEditor(document.getElementById("div_editor1"));
            editor1.attachEvent("change", function () {
                document.getElementById("inp_htmlcode").value = editor1.getHTMLCode();
            });
        </script>
    </form>
</body>
</html>


Default.aspx 這樣寫也可以
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="RTETest.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />
	<script type="text/javascript" src="/richtexteditor/rte.js"></script>
	<script type="text/javascript" src='/richtexteditor/plugins/all_plugins.js'></script>
</head>
<body>
    <form id="form1" runat="server">
        <div id="div_editor1" class="richtexteditor" style="width: 960px; margin: 0 auto;"></div>--%>
        <asp:TextBox ID="TextBox1" runat="server" TextMode="MultiLine" Rows="5" Columns="80"></asp:TextBox>
        <script>
            var editor1 = new RichTextEditor('TextBox1');
        </script>
    </form>
</body>
</html>


(下圖) 執行結果


(下圖) 定價

https://richtexteditor.com/pricing.aspx


(完)