Skip to content

Commit

Permalink
decrypt and process key at client side
Browse files Browse the repository at this point in the history
  • Loading branch information
polymorpher committed Nov 12, 2023
1 parent a2244a6 commit b6f6a8a
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 9 deletions.
17 changes: 17 additions & 0 deletions voice/voice-ai/Voice AI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
CD0D13672ADA74C800031EDD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0D13662ADA74C800031EDD /* CoreAudio.framework */; };
CD0D13692ADA74D100031EDD /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0D13682ADA74D100031EDD /* AVFoundation.framework */; };
CD0D136B2ADB28CE00031EDD /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CD0D136A2ADB28CE00031EDD /* logo.png */; };
CD8A1A652B0084C400A5B2CC /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = CD8A1A642B0084C400A5B2CC /* CryptoSwift */; };
F610490A2AF02D820087F745 /* OpenAIStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61049092AF02D820087F745 /* OpenAIStreamService.swift */; };
F610490B2AF02D820087F745 /* OpenAIStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61049092AF02D820087F745 /* OpenAIStreamService.swift */; };
F610490C2AF02D820087F745 /* OpenAIStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61049092AF02D820087F745 /* OpenAIStreamService.swift */; };
Expand Down Expand Up @@ -318,6 +319,7 @@
buildActionMask = 2147483647;
files = (
F61049102AF02DEE0087F745 /* SwiftyJSON in Frameworks */,
CD8A1A652B0084C400A5B2CC /* CryptoSwift in Frameworks */,
F67E43322AFAC166001B72CD /* SentrySwiftUI in Frameworks */,
CD0D13692ADA74D100031EDD /* AVFoundation.framework in Frameworks */,
B9B331A32AFB849000F6A9C9 /* StoreKit.framework in Frameworks */,
Expand Down Expand Up @@ -702,6 +704,7 @@
F610490F2AF02DEE0087F745 /* SwiftyJSON */,
F67E43312AFAC166001B72CD /* SentrySwiftUI */,
F67E43332AFAC16C001B72CD /* Sentry */,
CD8A1A642B0084C400A5B2CC /* CryptoSwift */,
);
productName = x;
productReference = CD0D13342ADA73B300031EDD /* Voice AI.app */;
Expand Down Expand Up @@ -793,6 +796,7 @@
packageReferences = (
F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
F67E43302AFAB71F001B72CD /* XCRemoteSwiftPackageReference "sentry-cocoa" */,
CD8A1A632B0084A900A5B2CC /* XCRemoteSwiftPackageReference "CryptoSwift" */,
);
productRefGroup = CD0D13352ADA73B300031EDD /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -1603,6 +1607,14 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
CD8A1A632B0084A900A5B2CC /* XCRemoteSwiftPackageReference "CryptoSwift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/krzyzanowskim/CryptoSwift.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.8.0;
};
};
F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON";
Expand All @@ -1627,6 +1639,11 @@
package = F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
productName = SwiftyJSON;
};
CD8A1A642B0084C400A5B2CC /* CryptoSwift */ = {
isa = XCSwiftPackageProductDependency;
package = CD8A1A632B0084A900A5B2CC /* XCRemoteSwiftPackageReference "CryptoSwift" */;
productName = CryptoSwift;
};
F610490F2AF02DEE0087F745 /* SwiftyJSON */ = {
isa = XCSwiftPackageProductDependency;
package = F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
{
"pins" : [
{
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e",
"version" : "1.8.0"
}
},
{
"identity" : "sentry-cocoa",
"kind" : "remoteSourceControl",
Expand Down
88 changes: 83 additions & 5 deletions voice/voice-ai/x/AppConfigration/AppConfig.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import CryptoSwift
import DeviceCheck
import Foundation
import Sentry
import SwiftyJSON

class AppConfig {
// Shared singleton instance
static let shared = AppConfig()
private var apiKey: String?
private var openaiKey: String?
private var relayUrl: String?
private var sharedEncryptionSecret: String?
private var sharedEncryptionIV: String?
private var deepgramKey: String?
private var minimumSignificantEvents: Int?
private var daysBetweenPrompts: Int?
Expand All @@ -16,6 +22,76 @@ class AppConfig {
self.loadConfiguration()
}

private func decrypt(base64EncodedEncryptedKey: String) throws -> String {
let d = Data(base64Encoded: base64EncodedEncryptedKey)
guard let d = d else {
throw NSError(domain: "Invalid encoded encrypted key", code: -1)
}
let encryptedKey = String(data: d, encoding: .utf8)
guard let encryptedKey = encryptedKey else {
throw NSError(domain: "Malformed key encoding", code: -2)
}
let iv: [UInt8] = Array(self.sharedEncryptionIV!.utf8)
let sharedKey: [UInt8] = Array(self.sharedEncryptionSecret!.utf8)
let aes = try AES(key: sharedKey, blockMode: GCM(iv: iv))
let dBytes = try aes.decrypt(encryptedKey.bytes)
let dKey = String(data: Data(dBytes), encoding: .utf8)
guard let key = dKey else {
throw NSError(domain: "Key is not a string", code: -3)
}
return key
}

private func requestOpenAIKey() async {
guard let relayUrl = self.relayUrl else {
print("Relay URL not set")
SentrySDK.capture(message: "Relay URL not set")
return
}
let s = URLSession(configuration: .default)
guard let url = URL(string: "\(relayUrl)/key") else {
let error = NSError(domain: "Invalid Relay URL", code: -1, userInfo: nil)
SentrySDK.capture(message: "Invalid Relay URL")
return
}
var token = ""
do {
let d = try await DCDevice.current.generateToken()
print("token", d)
token = d.base64EncodedString()
} catch {
SentrySDK.capture(message: "Error generating device token")
print(error)
return
}
var r = URLRequest(url: url)
r.setValue(token, forHTTPHeaderField: "X-DEVICE-TOKEN")
s.dataTask(with: r) { data, _, err in
if let err = err {
print("[AppConfig][requestOpenAIKey] cannot get key", err)
SentrySDK.capture(message: "Cannot get key. Error: \(err)")
return
}
do {
let res = try JSON(data: data!)
let eeKey = res["key"].string
guard let eeKey = eeKey else {
print("[AppConfig][requestOpenAIKey] response has no key", res)
SentrySDK.capture(message: "[AppConfig][requestOpenAIKey] response has no key")
return
}
// TODO: decrypt key
let key = try self.decrypt(base64EncodedEncryptedKey: eeKey)
self.openaiKey = key
print("Got key", key)
} catch {
print("[AppConfig][requestOpenAIKey] error processing key response", error)
SentrySDK.capture(message: "[AppConfig][requestOpenAIKey] error processing key response \(error)")
}
}
// s.dataTask(with: "")
}

private func loadConfiguration() {
guard let path = Bundle.main.path(forResource: "AppConfig", ofType: "plist") else {
fatalError("Unable to locate plist file")
Expand All @@ -29,10 +105,12 @@ class AppConfig {
fatalError("Unable to convert plist into dictionary")
}

self.apiKey = dictionary["API_KEY"]

self.sentryDSN = dictionary["SENTRY_DSN"]

self.sharedEncryptionSecret = dictionary["SHARED_ENCRYPTION_SECRET"]
self.sharedEncryptionIV = dictionary["SHARED_ENCRYPTION_IV"]
self.relayUrl = dictionary["RELAY_URL"]

self.themeName = dictionary["THEME_NAME"]
self.deepgramKey = dictionary["DEEPGRAM_KEY"]

Expand All @@ -55,8 +133,8 @@ class AppConfig {
}
}

func getAPIKey() -> String? {
return self.apiKey
func getOpenAIKey() -> String? {
return self.openaiKey
}

func getSentryDSN() -> String? {
Expand Down
2 changes: 1 addition & 1 deletion voice/voice-ai/x/OpenAIService/OpenAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct OpenAIService {
// private var conversation: [Message]
// Function to send input text to OpenAI for processing
mutating func sendToOpenAI(conversation: [Message], completion: @escaping (String?, Error?) -> Void) {
guard let openAI_APIKey = AppConfig.shared.getAPIKey() else {
guard let openAI_APIKey = AppConfig.shared.getOpenAIKey() else {
completion(nil, nil)
SentrySDK.capture(message: "Open AI Api key is null")
return
Expand Down
2 changes: 1 addition & 1 deletion voice/voice-ai/x/OpenAIService/OpenAIStreamService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ protocol NetworkService {
class OpenAIStreamService: NSObject, URLSessionDataDelegate {
private var task: URLSessionDataTask?
private var completion: (String?, Error?) -> Void
private let apiKey = AppConfig.shared.getAPIKey()
private let apiKey = AppConfig.shared.getOpenAIKey()
private var temperature: Double
private let networkService: NetworkService?

Expand Down
4 changes: 2 additions & 2 deletions voice/voice-ai/xTests/AppConfigTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AppConfigTests: XCTestCase {
}

func testAPIKeyIsNotNil() {
XCTAssertNotNil(appConfig.getAPIKey(), "API Key should not be nil")
XCTAssertNotNil(appConfig.getOpenAIKey(), "API Key should not be nil")
}

func testDeepgramKeyIsNotNil() {
Expand All @@ -40,7 +40,7 @@ class AppConfigTests: XCTestCase {
}

func testLoadingValidPlistFile() {
XCTAssertNotNil(appConfig.getAPIKey(), "API Key should not be nil")
XCTAssertNotNil(appConfig.getOpenAIKey(), "API Key should not be nil")
XCTAssertNotNil(appConfig.getDeepgramKey(), "Deepgram Key should not be nil")
XCTAssertNotNil(appConfig.getThemeName(), "Theme Name should not be nil")
// XCTAssertNotNil(appConfig.getSentryDSN(), "Sentry DSN should not be nil")
Expand Down

0 comments on commit b6f6a8a

Please sign in to comment.