From 660a75ab863060845bbbd990f1e54289180e1821 Mon Sep 17 00:00:00 2001 From: tisfeng Date: Thu, 15 Feb 2024 16:31:22 +0800 Subject: [PATCH] refactor: store secret key in EncryptedSecretKeys.plist --- Easydict.xcodeproj/project.pbxproj | 30 +++++- Easydict/App/Easydict-Bridging-Header.h | 1 + .../Service/Niutrans/EZNiuTransTranslate.m | 3 - .../Service/OpenAI/EZObjcOpenAIService.m | 10 +- Easydict/Feature/Utility/EZLog/EZLog.m | 4 +- .../Service/Caiyun/CaiyunService.swift | 7 +- .../Service/Gemini/GeminiService.swift | 2 - .../Service/OpenAI/OpenAIService.swift | 18 +--- .../Service/OpenAI/Prompt.swift | 0 .../Service/Tencent/TencentService.swift | 10 -- .../Utility/DefaultAPIKeys/APIKey.swift | 98 +++++++++++++++++++ .../DefaultAPIKeys/EncryptedSecretKeys.plist | 22 +++++ 12 files changed, 155 insertions(+), 50 deletions(-) rename Easydict/{Feature => SwiftApp}/Service/OpenAI/OpenAIService.swift (86%) rename Easydict/{Feature => SwiftApp}/Service/OpenAI/Prompt.swift (100%) create mode 100644 Easydict/SwiftApp/Utility/DefaultAPIKeys/APIKey.swift create mode 100644 Easydict/SwiftApp/Utility/DefaultAPIKeys/EncryptedSecretKeys.plist diff --git a/Easydict.xcodeproj/project.pbxproj b/Easydict.xcodeproj/project.pbxproj index 1cfaac2fb..e8f3c3366 100644 --- a/Easydict.xcodeproj/project.pbxproj +++ b/Easydict.xcodeproj/project.pbxproj @@ -231,6 +231,8 @@ 03F25CB329327BC200E66A12 /* EZShortcut.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F25CB229327BC200E66A12 /* EZShortcut.m */; }; 03F639952AA6CFBB009B9914 /* EZBingConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F639942AA6CFBB009B9914 /* EZBingConfig.m */; }; 03FB3EDD2B1B405B004C3238 /* TencentSigning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FB3EDC2B1B405B004C3238 /* TencentSigning.swift */; }; + 03FC57C72B7DCED300E036F3 /* EncryptedSecretKeys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03FC57C62B7DCED300E036F3 /* EncryptedSecretKeys.plist */; }; + 03FC57CA2B7DD05D00E036F3 /* APIKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FC57C92B7DD05D00E036F3 /* APIKey.swift */; }; 03FC699A2B39D13A0035D2DA /* EZOpenAIChatResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FC69992B39D13A0035D2DA /* EZOpenAIChatResponse.m */; }; 03FD68BB2B1DC59600FD388E /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 03FD68BA2B1DC59600FD388E /* CryptoSwift */; }; 03FD68BE2B1E151A00FD388E /* String+EncryptAES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FD68BD2B1E151A00FD388E /* String+EncryptAES.swift */; }; @@ -743,6 +745,8 @@ 03F639932AA6CFBB009B9914 /* EZBingConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZBingConfig.h; sourceTree = ""; }; 03F639942AA6CFBB009B9914 /* EZBingConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZBingConfig.m; sourceTree = ""; }; 03FB3EDC2B1B405B004C3238 /* TencentSigning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentSigning.swift; sourceTree = ""; }; + 03FC57C62B7DCED300E036F3 /* EncryptedSecretKeys.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = EncryptedSecretKeys.plist; sourceTree = ""; }; + 03FC57C92B7DD05D00E036F3 /* APIKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIKey.swift; sourceTree = ""; }; 03FC69962B399EF00035D2DA /* EZOpenAIChatResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZOpenAIChatResponse.h; sourceTree = ""; }; 03FC69992B39D13A0035D2DA /* EZOpenAIChatResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZOpenAIChatResponse.m; sourceTree = ""; }; 03FD68BD2B1E151A00FD388E /* String+EncryptAES.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+EncryptAES.swift"; sourceTree = ""; }; @@ -1298,8 +1302,6 @@ 0399C6A929A8608000B4AFCC /* OpenAI */ = { isa = PBXGroup; children = ( - 0342801C2B41A01F002AF60D /* OpenAIService.swift */, - 034280212B4308D2002AF60D /* Prompt.swift */, 0399C6AA29A860AA00B4AFCC /* EZObjcOpenAIService.h */, 0399C6AB29A860AA00B4AFCC /* EZObjcOpenAIService.m */, 03FC69962B399EF00035D2DA /* EZOpenAIChatResponse.h */, @@ -2083,10 +2085,11 @@ 03FC57C32B7DCAE400E036F3 /* Service */ = { isa = PBXGroup; children = ( + 03FC57C82B7DCFBA00E036F3 /* OpenAI */, + C415C0AB2B450C4500A9D231 /* Gemini */, 62E2BF462B4082BA00E42D38 /* Ali */, 2746AEBF2AF95040005FE0A1 /* Caiyun */, C4DD01E72B12B3B00025EE8E /* Tencent */, - C415C0AB2B450C4500A9D231 /* Gemini */, ); path = Service; sourceTree = ""; @@ -2100,6 +2103,24 @@ path = App; sourceTree = ""; }; + 03FC57C52B7DCE8300E036F3 /* DefaultAPIKeys */ = { + isa = PBXGroup; + children = ( + 03FC57C92B7DD05D00E036F3 /* APIKey.swift */, + 03FC57C62B7DCED300E036F3 /* EncryptedSecretKeys.plist */, + ); + path = DefaultAPIKeys; + sourceTree = ""; + }; + 03FC57C82B7DCFBA00E036F3 /* OpenAI */ = { + isa = PBXGroup; + children = ( + 0342801C2B41A01F002AF60D /* OpenAIService.swift */, + 034280212B4308D2002AF60D /* Prompt.swift */, + ); + path = OpenAI; + sourceTree = ""; + }; 03FD68BC2B1E14B500FD388E /* String */ = { isa = PBXGroup; children = ( @@ -2398,6 +2419,7 @@ children = ( EAE3D34F2B62E9DE001EE3E3 /* GlobalContext.swift */, DC6D9C882B3969510055EFFC /* Appearance.swift */, + 03FC57C52B7DCE8300E036F3 /* DefaultAPIKeys */, EAED41ED2B54B1390005FE0A /* Protocol */, EA9943E62B534D7C00EE7B97 /* Extensions */, ); @@ -2666,6 +2688,7 @@ 0310C8272A94F5DF00B1D81E /* apple-dictionary.html in Resources */, 03BFBB802923A2FA00C48725 /* white-black-icon@2x.png in Resources */, 031DBD792AE01E130071CF85 /* easydict in Resources */, + 03FC57C72B7DCED300E036F3 /* EncryptedSecretKeys.plist in Resources */, 03BFBB7329239E9F00C48725 /* blue-white-icon@2x.png in Resources */, 03882F9229D95044005B5A52 /* Info.plist in Resources */, 03BFBB7C2923A1D900C48725 /* cyan-white-icon@3x.png in Resources */, @@ -2916,6 +2939,7 @@ 03BD281E29481C0400F5891A /* EZAudioPlayer.m in Sources */, 0A8685C82B552A590022534F /* DisabledAppTab.swift in Sources */, 9643D94A2B71EABE000FBEA6 /* KeyHolderAlterView.swift in Sources */, + 03FC57CA2B7DD05D00E036F3 /* APIKey.swift in Sources */, 03E02A2629250D1D00A10260 /* EZEventMonitor.m in Sources */, 03B0233429231FA6001C7E63 /* MMConsoleLogFormatter.m in Sources */, 037852B9295D49F900D0E2CF /* EZTableRowView.m in Sources */, diff --git a/Easydict/App/Easydict-Bridging-Header.h b/Easydict/App/Easydict-Bridging-Header.h index d9f446179..26e7943b8 100644 --- a/Easydict/App/Easydict-Bridging-Header.h +++ b/Easydict/App/Easydict-Bridging-Header.h @@ -34,3 +34,4 @@ #import "EZNiuTransTranslate.h" #import "EZDeepLTranslate.h" #import "EZBingService.h" +#import "EZObjcOpenAIService.h" diff --git a/Easydict/Feature/Service/Niutrans/EZNiuTransTranslate.m b/Easydict/Feature/Service/Niutrans/EZNiuTransTranslate.m index 839737895..c1ba0792d 100644 --- a/Easydict/Feature/Service/Niutrans/EZNiuTransTranslate.m +++ b/Easydict/Feature/Service/Niutrans/EZNiuTransTranslate.m @@ -12,7 +12,6 @@ @interface EZNiuTransTranslate () -@property (nonatomic, copy) NSString *defaultAPIKey; @property (nonatomic, copy) NSString *apiKey; @end @@ -21,8 +20,6 @@ @implementation EZNiuTransTranslate - (instancetype)init { if (self = [super init]) { - // This is a test APIKey, please do not abuse it. It is recommended to go to the official website to apply for a personal APIKey. - self.defaultAPIKey = [@"XOoEyjDMoM2MuMInzySOjGucFWXRj1wXQivVYDGTi6X7iDe7EkuHVVPOy2Op3RlD" decryptAES]; } return self; } diff --git a/Easydict/Feature/Service/OpenAI/EZObjcOpenAIService.m b/Easydict/Feature/Service/OpenAI/EZObjcOpenAIService.m index 1a19a74b1..319a468c8 100644 --- a/Easydict/Feature/Service/OpenAI/EZObjcOpenAIService.m +++ b/Easydict/Feature/Service/OpenAI/EZObjcOpenAIService.m @@ -22,7 +22,6 @@ @interface EZObjcOpenAIService () @property (nonatomic, copy) NSString *model; @property (nonatomic, copy) NSString *domain; -@property (nonatomic, copy) NSString *defaultAPIKey; @property (nonatomic, copy) NSString *defaultEndPoint; @property (nonatomic, copy) NSString *defaultModel; @@ -39,14 +38,7 @@ - (instancetype)init { For better experience, please apply for your personal key at https://makersuite.google.com/app/apikey */ - - // Only use Google Gemini-pro channel - self.defaultAPIKey = [@"NnZp/jV9prt5empCOJIM8LmzHmFdTiVa4i+mURU8t+uGpT+nDt/JTdf14JglJLEwVm8Sup83uzJjMANeEvyPcw==" decryptAES]; - -#if DEBUG - self.defaultAPIKey = [@"NnZp/jV9prt5empCOJIM8LmzHmFdTiVa4i+mURU8t+uGpT+nDt/JTdf14JglJLEwpXkkSw+uGgiE8n5skqDdjQ==" decryptAES]; -#endif - self.defaultEndPoint = [@"gTYTMVQTyMU0ogncqcMNRo/TDhten/V4TqX4IutuGNcYTLtxjgl/aXB/Y1NXAjz2" decryptAES]; + self.defaultModel = [self hasPrivateAPIKey] ? @"gpt-3.5-turbo-1106" : @"gemini-pro"; } return self; diff --git a/Easydict/Feature/Utility/EZLog/EZLog.m b/Easydict/Feature/Utility/EZLog/EZLog.m index c17f1e7b9..19ba8ec44 100644 --- a/Easydict/Feature/Utility/EZLog/EZLog.m +++ b/Easydict/Feature/Utility/EZLog/EZLog.m @@ -20,9 +20,11 @@ @implementation EZLog + (void)setupCrashLogService { + // Enable statistics only in non-debug mode. + #if !DEBUG // App Center - [MSACAppCenter start:[@"WJFbwsYrXm9olzfwt6dgXHRh0hs8OjT8etWAuZH/nSXpXuRgQgvkh14oyHhkFkme" decryptAES] withServices:@[ + [MSACAppCenter start:SecretKeyManager.keyValues[@"appcenterSecret"] withServices:@[ [MSACAnalytics class], [MSACCrashes class] ]]; diff --git a/Easydict/SwiftApp/Service/Caiyun/CaiyunService.swift b/Easydict/SwiftApp/Service/Caiyun/CaiyunService.swift index 55a2d8b74..bd1ce69e6 100644 --- a/Easydict/SwiftApp/Service/Caiyun/CaiyunService.swift +++ b/Easydict/SwiftApp/Service/Caiyun/CaiyunService.swift @@ -39,21 +39,18 @@ public final class CaiyunService: QueryService { } override public func hasPrivateAPIKey() -> Bool { - token != CaiyunService.defaultTestToken + token != defaultToken } private var apiEndPoint = "https://api.interpreter.caiyunai.com/v1/translator" - /// Official Test Token for Caiyun - private static let defaultTestToken = "5VZ61ZCRzQ2uTbp6MPaUGdoqXGklkB3WifIBPamAwLc=".decryptAES() - // easydict://writeKeyValue?EZCaiyunToken= private var token: String { let token = Defaults[.caiyunToken] if let token, !token.isEmpty { return token } else { - return CaiyunService.defaultTestToken + return defaultToken } } diff --git a/Easydict/SwiftApp/Service/Gemini/GeminiService.swift b/Easydict/SwiftApp/Service/Gemini/GeminiService.swift index 43331a553..9e1f2e2dd 100644 --- a/Easydict/SwiftApp/Service/Gemini/GeminiService.swift +++ b/Easydict/SwiftApp/Service/Gemini/GeminiService.swift @@ -56,8 +56,6 @@ public final class GeminiService: QueryService { return true } - private let defaultAPIKey = "" /* .decryptAES() */ - // easydict://writeKeyValue?EZGeminiAPIKey=xxx private var apiKey: String { let apiKey = Defaults[.geminiAPIKey] diff --git a/Easydict/Feature/Service/OpenAI/OpenAIService.swift b/Easydict/SwiftApp/Service/OpenAI/OpenAIService.swift similarity index 86% rename from Easydict/Feature/Service/OpenAI/OpenAIService.swift rename to Easydict/SwiftApp/Service/OpenAI/OpenAIService.swift index 3b323d1c8..7ba516861 100644 --- a/Easydict/Feature/Service/OpenAI/OpenAIService.swift +++ b/Easydict/SwiftApp/Service/OpenAI/OpenAIService.swift @@ -11,22 +11,6 @@ import OpenAI @objc(EZOpenAIService) public class OpenAIService: QueryService { - private var defaultAPIKey: String { - /** - For convenience, we provide a default key for users to try out the service. - - Please do not abuse it, otherwise it may be revoked. - - For better experience, please apply for your personal key at https://makersuite.google.com/app/apikey - */ - - var apiKey = ("NnZp/jV9prt5empCOJIM8LmzHmFdTiVa4i+mURU8t+" + "uGpT+nDt/JTdf14JglJLEwVm8Sup83uzJjMANeEvyPcw==").decryptAES() - #if DEBUG - apiKey = ("NnZp/jV9prt5empCOJIM8LmzHmFdTiVa4i+mURU8t+" + "uGpT+nDt/JTdf14JglJLEwpXkkSw+uGgiE8n5skqDdjQ==").decryptAES() - #endif - return apiKey - } - private var apiKey: String { // easydict://writeKeyValue?EZOpenAIAPIKey= @@ -47,7 +31,7 @@ public class OpenAIService: QueryService { } if !hasPrivateAPIKey() { - endPoint = "gTYTMVQTyMU0ogncqcMNRo/TDhten/V4TqX4IutuGNcYTLtxjgl/aXB/Y1NXAjz2".decryptAES() + endPoint = defaultEndPoint } return endPoint diff --git a/Easydict/Feature/Service/OpenAI/Prompt.swift b/Easydict/SwiftApp/Service/OpenAI/Prompt.swift similarity index 100% rename from Easydict/Feature/Service/OpenAI/Prompt.swift rename to Easydict/SwiftApp/Service/OpenAI/Prompt.swift diff --git a/Easydict/SwiftApp/Service/Tencent/TencentService.swift b/Easydict/SwiftApp/Service/Tencent/TencentService.swift index aaa07b9ab..cc1a82e1a 100644 --- a/Easydict/SwiftApp/Service/Tencent/TencentService.swift +++ b/Easydict/SwiftApp/Service/Tencent/TencentService.swift @@ -53,16 +53,6 @@ public final class TencentService: QueryService { 500 * 10000 } - /** - For convenience, we provide a default key for users to try out the service. - - Please do not abuse it, otherwise it may be revoked. - - For better experience, please apply for your personal key at https://cloud.tencent.com - */ - private let defaultSecretId = "7ZdGkHHIx4Nozm4RHib5Jjye5yCefYoxxfSWzMRbKRrHrnSEJaqpypL1yRMoN0E5".decryptAES() - private let defaultSecretKey = "OLvQKqJoBfrfLLg95ezIQsWymT+2irYbuMLov1cxrtc3a/M2YXCDQ2rpyy/raQ8r".decryptAES() - // easydict://writeKeyValue?EZTencentSecretId=xxx private var secretId: String { let secretId = Defaults[.tencentSecretId] diff --git a/Easydict/SwiftApp/Utility/DefaultAPIKeys/APIKey.swift b/Easydict/SwiftApp/Utility/DefaultAPIKeys/APIKey.swift new file mode 100644 index 000000000..07b86c31c --- /dev/null +++ b/Easydict/SwiftApp/Utility/DefaultAPIKeys/APIKey.swift @@ -0,0 +1,98 @@ +// +// APIKey.swift +// Easydict +// +// Created by tisfeng on 2024/2/15. +// Copyright © 2024 izual. All rights reserved. +// + +import Defaults +import Foundation + +extension OpenAIService { + var defaultAPIKey: String { + APIKey.openAIAPIKey.stringValue + } + + var defaultEndPoint: String { + APIKey.openAIEndPoint.stringValue + } +} + +extension EZObjcOpenAIService { + @objc var defaultAPIKey: String { + APIKey.openAIAPIKey.stringValue + } + + @objc var defaultEndPoint: String { + APIKey.openAIEndPoint.stringValue + } +} + +extension GeminiService { + var defaultAPIKey: String { + APIKey.geminiAPIKey.stringValue + } +} + +extension CaiyunService { + var defaultToken: String { + APIKey.caiyunToken.stringValue + } +} + +extension TencentService { + var defaultSecretId: String { + APIKey.tencentSecretId.stringValue + } + + var defaultSecretKey: String { + APIKey.tencentSecretKey.stringValue + } +} + +extension EZNiuTransTranslate { + @objc var defaultAPIKey: String { + APIKey.niutransAPIKey.stringValue + } +} + +enum APIKey: String { + /** + For convenience, we provide a default key for users to try out the service. + Please do not abuse it, otherwise it may be revoked. + */ + + case openAIAPIKey + case openAIEndPoint + case geminiAPIKey + case caiyunToken + case tencentSecretId + case tencentSecretKey + case niutransAPIKey + + var stringValue: String { + SecretKeyManager.keyValues[rawValue] ?? "" + } +} + +@objcMembers class SecretKeyManager: NSObject { + static var keyValues: [String: String] { + guard let path = Bundle.main.path(forResource: "EncryptedSecretKeys", ofType: "plist") else { + return [:] + } + + guard let dict = NSDictionary(contentsOfFile: path) else { + return [:] + } + + var decryptedKeyValues = [String: String]() + for (key, value) in dict { + if let key = key as? String, let value = value as? String { + decryptedKeyValues[key] = value.decryptAES() + } + } + + return decryptedKeyValues + } +} diff --git a/Easydict/SwiftApp/Utility/DefaultAPIKeys/EncryptedSecretKeys.plist b/Easydict/SwiftApp/Utility/DefaultAPIKeys/EncryptedSecretKeys.plist new file mode 100644 index 000000000..4df18c08a --- /dev/null +++ b/Easydict/SwiftApp/Utility/DefaultAPIKeys/EncryptedSecretKeys.plist @@ -0,0 +1,22 @@ + + + + + niutransAPIKey + XOoEyjDMoM2MuMInzySOjGucFWXRj1wXQivVYDGTi6X7iDe7EkuHVVPOy2Op3RlD + tencentSecretId + 7ZdGkHHIx4Nozm4RHib5Jjye5yCefYoxxfSWzMRbKRrHrnSEJaqpypL1yRMoN0E5 + tencentSecretKey + OLvQKqJoBfrfLLg95ezIQsWymT+2irYbuMLov1cxrtc3a/M2YXCDQ2rpyy/raQ8r + caiyunToken + 5VZ61ZCRzQ2uTbp6MPaUGdoqXGklkB3WifIBPamAwLc= + geminiAPIKey + Hw20aVKaud8qfP5UZbNWUdUQkkzhOcYiIlku+jWl5lL+/lWZYQzeKNAlxiQJh1B5 + openAIAPIKey + NnZp/jV9prt5empCOJIM8LmzHmFdTiVa4i+mURU8t+uGpT+nDt/JTdf14JglJLEwVm8Sup83uzJjMANeEvyPcw== + openAIEndPoint + gTYTMVQTyMU0ogncqcMNRo/TDhten/V4TqX4IutuGNcYTLtxjgl/aXB/Y1NXAjz2 + appcenterSecret + WJFbwsYrXm9olzfwt6dgXHRh0hs8OjT8etWAuZH/nSXpXuRgQgvkh14oyHhkFkme + +