feat(account): add managed credits and cloud gateway

Introduce optional Apple account-backed credits with scoped gateway access while preserving local and BYOK paths. Refresh assistant behavior, tests, privacy disclosures, docs, and the website for the 2.0 experience.
This commit is contained in:
Rocky
2026-08-20 11:43:21 +08:00
parent 0f9280bd00
commit 498f407585
301 changed files with 19221 additions and 10891 deletions
@@ -0,0 +1,78 @@
// AccountSecurityPrimitiveTests.swift
// OSGKeyboardTests
//
// Fixed vectors for nonce hashing, canonical payloads, and Keychain isolation.
@testable import OSGKeyboardHostSupport
import XCTest
final class AccountSecurityPrimitiveTests: XCTestCase {
func testNonceUsesRawBase64URLAndLowercaseSHA256Hex() throws {
let bytes = Data(0..<32)
let generator = AppleSignInNonceGenerator(
random: FixedRandomBytesGenerator(value: bytes)
)
let nonce = try generator.makeNonce()
XCTAssertEqual(
nonce.rawValue,
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8"
)
XCTAssertEqual(
nonce.sha256Hex,
"ea866a757e4c38babfa8127cbe9a409d3e1f93a00ff1488ff735fcf917afffd0"
)
XCTAssertNotNil(
nonce.sha256Hex.range(
of: #"^[0-9a-f]{64}$"#,
options: .regularExpression
)
)
}
func testAppleSignInCanonicalPayloadMatchesServerByteForByte() throws {
let payload = try AppAttestCanonicalPayload.appleSignIn(
challenge: "AQID",
credential: AppleSignInCredential(
identityToken: "identity-token",
authorizationCode: "authorization-code"
),
rawNonce: "raw-nonce"
)
XCTAssertEqual(
String(data: payload, encoding: .utf8),
"""
osg-app-attest-v1
purpose=apple-sign-in
challenge=AQID
identity_token_sha256=OcwzHhEgHO3_IBV8hI8o_WTuAx0hgRrERJAbfcPbjvA
authorization_code_sha256=WVYUJ4163Fe7kuKPogOooY15egdoT9_3XLvyqW6_hXc
nonce_sha256=LF0QeTgFOiJ18CLBU8mnH2XuB3VLi8pUPul6DDzGaZA
"""
)
XCTAssertEqual(payload.last, 0x0A, "The server contract includes the final line feed")
}
func testHostPrivateKeychainDescriptorRejectsSharedAccessGroup() throws {
XCTAssertThrowsError(
try HostPrivateAccountKeychainDescriptor(
accessGroup: "TEAMID.com.osgkeyboard.shared"
)
)
let descriptor = try HostPrivateAccountKeychainDescriptor.hostApplication(
appIdentifierPrefix: "TEAMID"
)
XCTAssertEqual(descriptor.service, "com.osgkeyboard.ios.account")
XCTAssertEqual(descriptor.accessGroup, "TEAMID.com.osgkeyboard.ios")
}
func testBase64URLRejectsNonCanonicalAlphabet() {
XCTAssertNil(Data(base64URLEncoded: "AQID="))
XCTAssertNil(Data(base64URLEncoded: "AQ+ID"))
XCTAssertEqual(Data(base64URLEncoded: "AQID"), Data([1, 2, 3]))
}
}