Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions FirebaseAI/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# 12.2.0
- [feature] Added support for returning thought summaries, which are synthesized
versions of a model's internal reasoning process. (#15096)
- [feature] Added a new configuration option to use limited-use App
Check tokens for attesting Firebase AI Logic requests. This enhances
security against replay attacks. To use this feature, configure it
explicitly via the new `useLimitedUseAppCheckTokens` parameter when
initializing `FirebaseAI`. We recommend migrating to limited-use
tokens now, so your app will be ready to take advantage of replay
protection when it becomes available for Firebase AI Logic. (#15099)
- [feature] Added support for limited-use tokens with Firebase App Check. These short-lived tokens
provide greater protection for the APIs that give you access to Gemini and Imagen models. Learn
how to [enable usage of limited-use tokens](https://firebase.google.com/docs/ai-logic/app-check).
(#15099)

# 12.0.0
- [feature] Added support for Grounding with Google Search. (#15014)
Expand Down
28 changes: 7 additions & 21 deletions FirebaseAI/Sources/FirebaseAI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,11 @@ public final class FirebaseAI: Sendable {
/// - backend: The backend API for the Firebase AI SDK; if not specified, uses the default
/// ``Backend/googleAI()`` (Gemini Developer API).
/// - useLimitedUseAppCheckTokens: When sending tokens to the backend, this option enables
/// the usage of App Check's limited-use tokens instead of the standard cached tokens.
///
/// A new limited-use tokens will be generated for each request; providing a smaller attack
/// surface for malicious parties to hijack tokens. When used alongside replay protection,
/// limited-use tokens are also _consumed_ after each request, ensuring they can't be used
/// again.
/// the usage of App Check's limited-use tokens instead of the standard cached tokens. To
/// learn more, see the docs for
/// [App Check in Firebase AI Logic](https://firebase.google.com/docs/ai-logic/app-check).
///
/// _This flag is set to `false` by default._
///
/// > Important: Replay protection is not currently supported for the FirebaseAI backend.
/// > While this feature is being developed, you can still migrate to using
/// > limited-use tokens. Because limited-use tokens are backwards compatible, you can still
/// > use them without replay protection. Due to their shorter TTL over standard App Check
/// > tokens, they still provide a security benefit.
/// >
/// > Migrating to limited-use tokens sooner minimizes disruption when support for replay
/// > protection is added.
/// - Returns: A `FirebaseAI` instance, configured with the custom `FirebaseApp`.
Expand Down Expand Up @@ -110,8 +100,7 @@ public final class FirebaseAI: Sendable {
tools: tools,
toolConfig: toolConfig,
systemInstruction: systemInstruction,
requestOptions: requestOptions,
useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
requestOptions: requestOptions
)
}

Expand Down Expand Up @@ -147,8 +136,7 @@ public final class FirebaseAI: Sendable {
apiConfig: apiConfig,
generationConfig: generationConfig,
safetySettings: safetySettings,
requestOptions: requestOptions,
useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
requestOptions: requestOptions
)
}

Expand All @@ -163,8 +151,6 @@ public final class FirebaseAI: Sendable {

let apiConfig: APIConfig

let useLimitedUseAppCheckTokens: Bool

/// A map of active `FirebaseAI` instances keyed by the `FirebaseApp` name and the `location`,
/// in the format `appName:location`.
private nonisolated(unsafe) static var instances: [InstanceKey: FirebaseAI] = [:]
Expand Down Expand Up @@ -227,11 +213,11 @@ public final class FirebaseAI: Sendable {
projectID: projectID,
apiKey: apiKey,
firebaseAppID: app.options.googleAppID,
firebaseApp: app
firebaseApp: app,
useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
)
self.apiConfig = apiConfig
self.location = location
self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens
}

func modelResourceName(modelName: String) -> String {
Expand Down
5 changes: 4 additions & 1 deletion FirebaseAI/Sources/FirebaseInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,22 @@ struct FirebaseInfo: Sendable {
let projectID: String
let apiKey: String
let firebaseAppID: String
let useLimitedUseAppCheckTokens: Bool
let app: FirebaseApp

init(appCheck: AppCheckInterop? = nil,
auth: AuthInterop? = nil,
projectID: String,
apiKey: String,
firebaseAppID: String,
firebaseApp: FirebaseApp) {
firebaseApp: FirebaseApp,
useLimitedUseAppCheckTokens: Bool) {
self.appCheck = appCheck
self.auth = auth
self.projectID = projectID
self.apiKey = apiKey
self.firebaseAppID = firebaseAppID
self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens
app = firebaseApp
}
}
9 changes: 3 additions & 6 deletions FirebaseAI/Sources/GenerativeAIService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,9 @@ struct GenerativeAIService {

private let urlSession: URLSession

private let useLimitedUseAppCheckTokens: Bool

init(firebaseInfo: FirebaseInfo, urlSession: URLSession, useLimitedUseAppCheckTokens: Bool) {
init(firebaseInfo: FirebaseInfo, urlSession: URLSession) {
self.firebaseInfo = firebaseInfo
self.urlSession = urlSession
self.useLimitedUseAppCheckTokens = useLimitedUseAppCheckTokens
}

func loadRequest<T: GenerativeAIRequest>(request: T) async throws -> T.Response {
Expand Down Expand Up @@ -212,7 +209,7 @@ struct GenerativeAIService {

private func fetchAppCheckToken(appCheck: AppCheckInterop) async throws
-> FIRAppCheckTokenResultInterop {
if useLimitedUseAppCheckTokens {
if firebaseInfo.useLimitedUseAppCheckTokens {
if let token = await getLimitedUseAppCheckToken(appCheck: appCheck) {
return token
}
Expand Down Expand Up @@ -242,7 +239,7 @@ struct GenerativeAIService {
Never
>) in
guard
useLimitedUseAppCheckTokens,
firebaseInfo.useLimitedUseAppCheckTokens,
// `getLimitedUseToken(completion:)` is an optional protocol method. Optional binding
// is performed to make sure `continuation` is called even if the method’s not implemented.
let limitedUseTokenClosure = appCheck.getLimitedUseToken
Expand Down
8 changes: 2 additions & 6 deletions FirebaseAI/Sources/GenerativeModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ public final class GenerativeModel: Sendable {
/// only text content is supported.
/// - requestOptions: Configuration parameters for sending requests to the backend.
/// - urlSession: The `URLSession` to use for requests; defaults to `URLSession.shared`.
/// - useLimitedUseAppCheckTokens: Use App Check's limited-use tokens instead of the standard
/// cached tokens.
init(modelName: String,
modelResourceName: String,
firebaseInfo: FirebaseInfo,
Expand All @@ -88,15 +86,13 @@ public final class GenerativeModel: Sendable {
toolConfig: ToolConfig? = nil,
systemInstruction: ModelContent? = nil,
requestOptions: RequestOptions,
urlSession: URLSession = GenAIURLSession.default,
useLimitedUseAppCheckTokens: Bool = false) {
urlSession: URLSession = GenAIURLSession.default) {
self.modelName = modelName
self.modelResourceName = modelResourceName
self.apiConfig = apiConfig
generativeAIService = GenerativeAIService(
firebaseInfo: firebaseInfo,
urlSession: urlSession,
useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
urlSession: urlSession
)
self.generationConfig = generationConfig
self.safetySettings = safetySettings
Expand Down
6 changes: 2 additions & 4 deletions FirebaseAI/Sources/Types/Public/Imagen/ImagenModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,12 @@ public final class ImagenModel {
generationConfig: ImagenGenerationConfig?,
safetySettings: ImagenSafetySettings?,
requestOptions: RequestOptions,
urlSession: URLSession = GenAIURLSession.default,
useLimitedUseAppCheckTokens: Bool = false) {
urlSession: URLSession = GenAIURLSession.default) {
self.modelResourceName = modelResourceName
self.apiConfig = apiConfig
generativeAIService = GenerativeAIService(
firebaseInfo: firebaseInfo,
urlSession: urlSession,
useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
urlSession: urlSession
)
self.generationConfig = generationConfig
self.safetySettings = safetySettings
Expand Down
3 changes: 2 additions & 1 deletion FirebaseAI/Tests/Unit/ChatTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ final class ChatTests: XCTestCase {
projectID: "my-project-id",
apiKey: "API_KEY",
firebaseAppID: "My app ID",
firebaseApp: app
firebaseApp: app,
useLimitedUseAppCheckTokens: false
),
apiConfig: FirebaseAI.defaultVertexAIAPIConfig,
tools: nil,
Expand Down
4 changes: 2 additions & 2 deletions FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,14 @@
modelName: testModelName,
modelResourceName: testModelResourceName,
firebaseInfo: GenerativeModelTestUtil.testFirebaseInfo(
appCheck: AppCheckInteropFake(token: appCheckToken)
appCheck: AppCheckInteropFake(token: appCheckToken),
useLimitedUseAppCheckTokens: true
),
apiConfig: apiConfig,
tools: nil,
requestOptions: RequestOptions(),
urlSession: urlSession,
useLimitedUseAppCheckTokens: true
)

Check failure on line 517 in FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift

View workflow job for this annotation

GitHub Actions / spm / spm (macos-14, Xcode_16.2, iOS)

unexpected ',' separator

Check failure on line 517 in FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift

View workflow job for this annotation

GitHub Actions / spm / spm (macos-14, Xcode_16.2, iOS)

unexpected ',' separator

Check failure on line 517 in FirebaseAI/Tests/Unit/GenerativeModelVertexAITests.swift

View workflow job for this annotation

GitHub Actions / spm / spm (macos-14, Xcode_16.2, iOS)

unexpected ',' separator
MockURLProtocol
.requestHandler = try GenerativeModelTestUtil.httpRequestHandler(
forResource: "unary-success-basic-reply-short",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ enum GenerativeModelTestUtil {

static func testFirebaseInfo(appCheck: AppCheckInterop? = nil,
auth: AuthInterop? = nil,
privateAppID: Bool = false) -> FirebaseInfo {
privateAppID: Bool = false,
useLimitedUseAppCheckTokens: Bool = false) -> FirebaseInfo {
let app = FirebaseApp(instanceWithName: "testApp",
options: FirebaseOptions(googleAppID: "ignore",
gcmSenderID: "ignore"))
Expand All @@ -114,7 +115,8 @@ enum GenerativeModelTestUtil {
projectID: "my-project-id",
apiKey: "API_KEY",
firebaseAppID: "My app ID",
firebaseApp: app
firebaseApp: app,
useLimitedUseAppCheckTokens: useLimitedUseAppCheckTokens
)
}
}
Expand Down
Loading