vChewing / vChewing-macOS

威注音輸入法 macOS 版,恐怕是截至目前為止在功能多樣性方面最強的第三方免費 macOS 系統專用輸入法,採純 Swift 語言寫就。威注音的著力點是盡可能在力所能及的範圍內將整個產品的功能做得更好用,搭配特製的簡體中文與繁體中文專用辭庫。是純粹的簡體中文注音輸入法(也內贈原生繁體中文輸入模式),更具諸多威注音特色功能。目前研發管理工作均在 CSDN GitCode 進行。
https://vchewing.github.io/
Other
303 stars 10 forks source link

旨在接納奇摩輸入法難民的續政計畫。 #499

Closed ShikiSuen closed 10 months ago

ShikiSuen commented 10 months ago

[該行動已宣告失敗]

macOS 14.2 缺少某些被奇摩輸入法硬依賴的 Objective-C API,直接導致奇摩輸入法本體罷工。

image

經過 Zonble 修復過的偏好設定 App 能運行,但因為奇摩輸入法本體罷工、而無法從奇摩輸入法本體取得使用者辭典資料。 (奇摩輸入法的偏好設定是單獨的 App,與輸入法本體之間使用 XPC 通訊。輸入法本體罷工,所以只會通訊失敗。) image

目前只能呼籲各位奇摩輸入法使用者在升級到今後的 macOS 14.2 之前趕緊匯出使用者辭典資料,但總會有大量的漏網之魚。 「提瓦特行動(Operation Teyvat)」就是要幫到這些漏網之魚。

以下內容因行動失敗而作廢:

由於此項行動不可避免地用到 OpenVanilla 的主程式碼或處理邏輯(與加密資料庫讀取有關),所以只會是一個單獨的新 App、而不是讓威注音內建該遷移功能。 App 名稱暫定為「奇摩續政助手(Kimo Continuity Helper)」,允許將奇摩輸入法的使用者語彙資料直接 dump 到威注音輸入法內、或者使用者指定的存檔位置。

ShikiSuen commented 10 months ago

目前的發現

奇摩輸入法的使用者辭典 db 是加密過的,路徑是:

~/Library/Application Support/Yahoo! KeyKey/SmartMandarinUserData.db

已知奇摩輸入法的使用者語彙資料的匯出順序:

  1. (Zonble 修復過的)奇摩輸入法偏好設定->詞彙管理->「匯出自訂詞資料庫」按鈕點擊之後,會發起 XPCConnection 呼叫 (any OpenVanillaLoader).exportUserPhraseDBToFile(_ path: NSString) 函式。

    - (IBAction)exportDatabase:(id)sender {
    id ovService;
    
    // ......
    ovService = [NSConnection
      rootProxyForConnectionWithRegisteredName:OPENVANILLA_DO_CONNECTION_NAME
                                            host:nil];
    // ......
    NSSavePanel *panel = [NSSavePanel savePanel];
    [panel setAllowedFileTypes:[NSArray arrayWithObjects:@"txt", nil]];
    [panel setExtensionHidden:NO];
    [panel setCanCreateDirectories:NO];
    [panel setNameFieldLabel:LFLSTR(@"Export As:")];
    [panel setRequiredFileType:@"txt"];
    [panel setTitle:LFLSTR(@"Export Database")];
    [panel setMessage:LFLSTR(@"Exporting your own customized phrases database.")];
    [panel setPrompt:LFLSTR(@"Export")];
    if ([panel runModal] == NSFileHandlingPanelOKButton) {
    NSString *path = [panel filename];
    if (ovService) {
      [ovService setProtocolForProxy:@protocol(OpenVanillaService)];
      bool rtn = [ovService exportUserPhraseDBToFile:path];
      if (rtn) {
        NSAlert *alert =
            [NSAlert alertWithMessageText:LFLSTR(@"Done!")
                            defaultButton:LFLSTR(@"OK")
                          alternateButton:nil
                              otherButton:nil
                informativeTextWithFormat:
                    LFLSTR(@"Your phrases are successfully exported.")];
        [alert setAlertStyle:NSInformationalAlertStyle];
        [alert beginSheetModalForWindow:window
                          modalDelegate:self
                         didEndSelector:nil
                            contextInfo:nil];
      } else {
        NSAlert *alert = [NSAlert
                 alertWithMessageText:LFLSTR(@"Error")
                        defaultButton:LFLSTR(@"OK")
                      alternateButton:nil
                          otherButton:nil
            informativeTextWithFormat:LFLSTR(@"Unable to export database.")];
        [alert setAlertStyle:NSWarningAlertStyle];
        [alert beginSheetModalForWindow:window
                          modalDelegate:self
                         didEndSelector:nil
                            contextInfo:nil];
      }
    }
    }
  2. (any OpenVanillaLoader).exportUserPhraseDBToFile(_ path: NSString) 函式會緊接著呼叫 BPMFUserPhraseHelper.OpenUserPhraseDB(&pathInfo, _loaderService)

- (bool)exportUserPhraseDBToFile:(NSString *)path {
  string ufn = [path UTF8String];
  OVPathInfo pathInfo = _loaderPolicy->modulePackagePathInfoFromPath("");
  OVSQLiteConnection *db =
      BPMFUserPhraseHelper::OpenUserPhraseDB(&pathInfo, _loaderService);
  if (!db) return false;

  bool result = BPMFUserPhraseHelper::Export(db, ufn);
  delete db;
  return result;
}
  1. BPMFUserPhraseHelper.OpenUserPhraseDB() 會呼叫 Takao -> KeyRing -> SQLiteCryptoInit -> ObtenirUserDonneCle() 來獲取密鑰。

https://github.com/YahooArchive/KeyKey/blob/81e05f070c070af65cac21e8da28ca4ff2d58905/YahooKeyKey-Source-1.1.2528/Frameworks/Manjusri/Source/BPMFUserPhraseHelper.cpp#L234-L251

OVSQLiteConnection* BPMFUserPhraseHelper::OpenUserPhraseDB(
    OVPathInfo* pathInfo, OVLoaderService* loaderService) {
  OVDirectoryHelper::CheckDirectory(pathInfo->writablePath);

  string filename =
      OVPathHelper::PathCat(pathInfo->writablePath, "SmartMandarinUserData.db");
  loaderService->logger("BPMFUserPhraseHelper")
      << "attempting to open " << filename << endl;
  OVSQLiteConnection* userDB = OVSQLiteConnection::Open(filename);

  #ifdef OVIMSMARTMANDARIN_USE_SQLITE_CRYPTO
    pair<char*, size_t> cle = ObtenirUserDonneCle();
    if (cle.first) {
        sqlite3_key(userDB->connection(), cle.first, (int)cle.second);
        free(cle.first);
    }
  #endif

  return userDB;
}
  1. ObtenirUserDonneCle() 會藉由牛頭人(Minotaur)服務呼叫 Minos.GetBack() 函式來讀取源碼內已有的常數、來生成密鑰:

https://github.com/YahooArchive/KeyKey/blob/81e05f070c070af65cac21e8da28ca4ff2d58905/YahooKeyKey-Source-1.1.2528/Distributions/Takao/Keyring/SQLiteCryptoInit.cpp#L73-L76

  1. 牛頭人模組會用到 OpenSSL 來解密正確的密鑰:

https://github.com/YahooArchive/KeyKey/blob/81e05f070c070af65cac21e8da28ca4ff2d58905/YahooKeyKey-Source-1.1.2528/Frameworks/Minotaur/Source/Minotaur.cpp#L68-L94

ShikiSuen commented 10 months ago

凶多吉少了:哪怕有密鑰陣列,因為無法搞到 SQLITE_CEROD 模組,所以根本無法解密。 其他的免費開放原始碼的 SQLite 使用手段都不給你任何填寫密碼的入口,且就算有也不一定與 CEROD 的加密相容。

只能藉由社群媒體影響力者呼籲各位奇摩輸入法使用者自行匯出 TXT。

已經升級到 macOS 14.2 Beta 無法降級的,可以用這個旁門左道:

/Users/使用者名稱/Library/Application Support/Yahoo! KeyKey/SmartMandarinUserData.db

這個檔案備份好,拿來置換掉 Windows 系統下的奇摩輸入法的這個檔案,然後在 Windows 系統下匯出使用者辭典。

該檔案在 Windows 系統下的位置是:

C:\Users\使用者名稱\AppData\Roaming\Yahoo! KeyKey\SmartMandarinUserData.db
image image

一定要匯出,因為這個 database 是用 SQLite CEROD 加密的,哪怕有密鑰也只能由使用 CEROD 的工具解讀。 但 CEROD 從 2012 年底開始不再免費,且授權費用昂貴。這也是奇摩注音專案結案的原因。

ShikiSuen commented 10 months ago

任務失敗,只能先關閉工單。


剛剛花了兩個小時研究了一下,感覺我再這樣浪費時間下去沒意義、且不可能有任何回報。

這個問題比較適合全台灣的 macOS 奇摩輸入法使用者們「共同籌資」、然後找 Zonble 解決問題。雖然現在在台灣的只有 Zonble 了,但 Zonble 在解決這個問題的時候理應獲得相當份量的收入。如果這裡牽涉到 CEROD 的授權費用的話,則也得藉由這個共同籌資來承擔。

如果 Zonble 不想解決的話,也可以用這些籌資來找其他的私人軟體開發公司、來製作+釋出相關的閉源工具(CEROD 現在不是開源軟體了,不交錢用了就觸法)。