-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Move iOS app into repo with public-only Convex sync and proprietary licensing #367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 105 commits
c052f67
7b5f2b7
0cc1cbf
7280c82
3997738
033252b
9debe35
b6e5dbc
a246726
5f5cdd7
cd848c0
6afe13b
4a4eefb
70656f7
4e7b732
6b905db
06f8d81
e1d5e70
ca1252c
0428c93
d35e9cd
53c2e9f
a70a36d
4541919
1332e3c
0a62d6f
59703af
e1830f6
93f29a3
f8f6bbb
d0d3bdd
520b4ed
953557b
aeb40a3
b908e5f
66324d5
d0afa9a
496fbe2
5d07362
f2b055b
797da21
4217092
0e38b3a
9688324
5695aa9
b7497e8
150fa3d
7c6a4b0
0948181
00d2d5a
7b2c504
ad3c334
8284691
8e3afd5
cadf01c
cbaa5e1
06e3ed6
71d876d
d1121e1
6ce2c7d
43d5830
b2cacff
274af05
5826954
8ebe743
22e1d61
f848c99
aa0e98b
71727ed
8e25526
7a20839
17b1333
3b9b766
a16709e
2e5da2f
2557476
e1de296
164f281
dc7f441
08b6e39
5973bbe
b777bc9
63b9200
fd23931
60670b1
1e93e44
f6a1d61
7c9f86f
d983b57
47dd639
a524077
10fed42
801f47c
fb428f6
110d3c6
36e1cff
057f5bb
2f0a112
598a41c
42a3e00
46fb971
aed0e7b
0f6b2a7
d22c813
db3db01
9a4fc2f
9fbf6c3
047f74b
f5d1bfc
6ad55e0
dd0bcd2
d3d99f9
64ab3a9
213964d
ad30e50
18fe4fa
1ac3801
d20fe1b
5464a5f
533ae1e
32b9a25
efcba9d
e4607bc
b0084e1
6ea8932
56327c0
0190346
bfbd93d
bd52403
86a66ca
0de127e
749c7b8
ca28f15
d138a63
8e73df0
646de9b
2e3cc4b
a4dc14a
9bf0466
d918362
8f30127
fb39b20
7dd37e0
c8790b3
1451fd3
490ec92
4c12077
4d57a27
aee65d4
3f71afc
4e8ed2f
39774a6
9444728
3a8b267
47a8235
c383797
295b4b2
94d5456
ef80b04
a7697ca
f430286
18a70b4
373e253
0b7bb52
9619698
87d5a10
91f335d
597c7f3
a1a63f4
f10ccf3
7682476
0b87a3f
199426c
e8c7313
400236a
fc89fc1
f7d37bc
23ff44a
82c94d0
e47031c
c8b634d
a5d425a
0950c44
81b7e55
df537d2
f4c610a
396ebcd
8f089f4
71c9743
c503f81
e6c7798
97ad01a
94134ee
4017899
4a4ca73
9202fe5
45b8b34
e81e53b
77ff67d
d6949c7
ee0e39a
0bb48e1
8ff6260
0dc7d56
dfc88dd
51fb525
4a21acb
0189bb5
a160c5b
804510c
54ecf65
b39a8c0
1094102
c47591f
54007d7
98765d3
89c4c87
ba459db
1bcafeb
eea2fcf
e4c81be
77c0246
0ad537f
d0d05a7
ef85bc5
8a6f9f4
30c2c87
e525cfd
fa33d48
58d5da5
5635f4d
6f6f65f
19f49b0
36f5003
9b58e3e
8582615
41af789
f80a062
ffc8a32
7a1430a
0feb004
e370ca4
2d13c04
984aae5
cab80d1
cbafa76
135bceb
d861301
8bfe8ce
9f8e981
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,22 @@ jobs: | |
| with: | ||
| go-version-file: daemon/remote/go.mod | ||
|
|
||
| - name: Install zig | ||
| run: | | ||
| set -euo pipefail | ||
| ZIG_REQUIRED="0.15.2" | ||
| if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then | ||
| echo "zig ${ZIG_REQUIRED} already installed" | ||
| else | ||
| echo "Installing zig ${ZIG_REQUIRED} from tarball" | ||
| curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-x86_64-linux-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Add integrity verification (checksum/signature) for the Zig tarball before extracting and installing it. Prompt for AI agents |
||
| tar xf /tmp/zig.tar.xz -C /tmp | ||
| sudo mv /tmp/zig-x86_64-linux-${ZIG_REQUIRED}/zig /usr/local/bin/zig | ||
| sudo rm -rf /usr/local/lib/zig | ||
| sudo mv /tmp/zig-x86_64-linux-${ZIG_REQUIRED}/lib /usr/local/lib/zig | ||
| zig version | ||
| fi | ||
|
|
||
| - name: Run remote daemon tests | ||
| working-directory: daemon/remote | ||
| run: go test ./... | ||
|
|
||
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # License Scope | ||
|
|
||
| Default repository license: | ||
| - `LICENSE` (GNU AGPL v3) applies to this repository except where a more | ||
| specific license file governs a subtree. | ||
|
|
||
| Directory-specific override: | ||
| - `ios/**` is governed by `ios/LICENSE` and is proprietary / all-rights-reserved. | ||
| - The AGPL license at `LICENSE` does not grant rights for files under `ios/**`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // swift-tools-version: 6.0 | ||
| import PackageDescription | ||
|
|
||
| let package = Package( | ||
| name: "CMUXAuthCore", | ||
| platforms: [ | ||
| .iOS(.v18), | ||
| .macOS(.v15), | ||
| ], | ||
| products: [ | ||
| .library( | ||
| name: "CMUXAuthCore", | ||
| targets: ["CMUXAuthCore"] | ||
| ), | ||
| ], | ||
| targets: [ | ||
| .target( | ||
| name: "CMUXAuthCore" | ||
| ), | ||
| .testTarget( | ||
| name: "CMUXAuthCoreTests", | ||
| dependencies: ["CMUXAuthCore"] | ||
| ), | ||
| ] | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import Foundation | ||
|
|
||
| public enum CMUXAuthEnvironment: Sendable { | ||
| case development | ||
| case production | ||
| } | ||
|
|
||
| public struct CMUXAuthConfig: Equatable, Sendable { | ||
| public let projectId: String | ||
| public let publishableClientKey: String | ||
|
|
||
| public init(projectId: String, publishableClientKey: String) { | ||
| self.projectId = projectId | ||
| self.publishableClientKey = publishableClientKey | ||
| } | ||
|
|
||
| public static func resolve( | ||
| environment: CMUXAuthEnvironment, | ||
| overrides: [String: String] = [:], | ||
| developmentProjectId: String, | ||
| productionProjectId: String, | ||
| developmentPublishableClientKey: String, | ||
| productionPublishableClientKey: String | ||
| ) -> Self { | ||
| let projectId: String | ||
| let publishableClientKey: String | ||
|
|
||
| switch environment { | ||
| case .development: | ||
| projectId = overrides["STACK_PROJECT_ID_DEV"] ?? developmentProjectId | ||
| publishableClientKey = overrides["STACK_PUBLISHABLE_CLIENT_KEY_DEV"] ?? developmentPublishableClientKey | ||
| case .production: | ||
| projectId = overrides["STACK_PROJECT_ID_PROD"] ?? productionProjectId | ||
| publishableClientKey = overrides["STACK_PUBLISHABLE_CLIENT_KEY_PROD"] ?? productionPublishableClientKey | ||
| } | ||
|
|
||
| return Self(projectId: projectId, publishableClientKey: publishableClientKey) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import Foundation | ||
|
|
||
| public final class CMUXAuthIdentityStore: @unchecked Sendable { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Avoid Prompt for AI agents |
||
| private let keyValueStore: CMUXAuthKeyValueStore | ||
| private let key: String | ||
| private let decoder = JSONDecoder() | ||
| private let encoder = JSONEncoder() | ||
|
|
||
| public init(keyValueStore: CMUXAuthKeyValueStore, key: String) { | ||
| self.keyValueStore = keyValueStore | ||
| self.key = key | ||
| } | ||
|
|
||
| public func save(_ user: CMUXAuthUser) throws { | ||
| let data = try encoder.encode(user) | ||
| keyValueStore.set(data, forKey: key) | ||
| } | ||
|
|
||
| public func load() throws -> CMUXAuthUser? { | ||
| guard let data = keyValueStore.data(forKey: key) else { | ||
| return nil | ||
| } | ||
| return try decoder.decode(CMUXAuthUser.self, from: data) | ||
| } | ||
|
|
||
| public func clear() { | ||
| keyValueStore.removeObject(forKey: key) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,32 @@ | ||||||
| import Foundation | ||||||
|
|
||||||
| public protocol CMUXAuthKeyValueStore: AnyObject { | ||||||
| func bool(forKey defaultName: String) -> Bool | ||||||
| func data(forKey defaultName: String) -> Data? | ||||||
| func set(_ value: Any?, forKey defaultName: String) | ||||||
| func removeObject(forKey defaultName: String) | ||||||
| } | ||||||
|
|
||||||
| extension UserDefaults: CMUXAuthKeyValueStore {} | ||||||
|
|
||||||
| public final class CMUXAuthSessionCache: @unchecked Sendable { | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Prompt for AI agents
Suggested change
|
||||||
| private let keyValueStore: CMUXAuthKeyValueStore | ||||||
| private let key: String | ||||||
|
|
||||||
| public init(keyValueStore: CMUXAuthKeyValueStore, key: String) { | ||||||
| self.keyValueStore = keyValueStore | ||||||
| self.key = key | ||||||
| } | ||||||
|
|
||||||
| public var hasTokens: Bool { | ||||||
| keyValueStore.bool(forKey: key) | ||||||
| } | ||||||
|
|
||||||
| public func setHasTokens(_ value: Bool) { | ||||||
| keyValueStore.set(value, forKey: key) | ||||||
| } | ||||||
|
|
||||||
| public func clear() { | ||||||
| keyValueStore.removeObject(forKey: key) | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| import Foundation | ||
|
|
||
| public struct CMUXAuthAutoLoginCredentials: Equatable, Sendable { | ||
| public let email: String | ||
| public let password: String | ||
|
|
||
| public init(email: String, password: String) { | ||
| self.email = email | ||
| self.password = password | ||
| } | ||
| } | ||
|
|
||
| public enum CMUXAuthLaunchConfig { | ||
| public static func autoLoginCredentials( | ||
| from environment: [String: String], | ||
| clearAuth: Bool, | ||
| mockDataEnabled: Bool | ||
| ) -> CMUXAuthAutoLoginCredentials? { | ||
| if clearAuth || mockDataEnabled { | ||
| return nil | ||
| } | ||
| guard let email = environment["CMUX_UITEST_STACK_EMAIL"], !email.isEmpty else { | ||
| return nil | ||
| } | ||
| guard let password = environment["CMUX_UITEST_STACK_PASSWORD"], !password.isEmpty else { | ||
| return nil | ||
| } | ||
| return CMUXAuthAutoLoginCredentials(email: email, password: password) | ||
| } | ||
|
|
||
| public static func fixtureUser( | ||
| from environment: [String: String], | ||
| clearAuth: Bool, | ||
| mockDataEnabled: Bool | ||
| ) -> CMUXAuthUser? { | ||
| if clearAuth || mockDataEnabled { | ||
| return nil | ||
| } | ||
| guard environment["CMUX_UITEST_AUTH_FIXTURE"] == "1" else { | ||
| return nil | ||
| } | ||
| return CMUXAuthUser( | ||
| id: environment["CMUX_UITEST_AUTH_USER_ID"] ?? "uitest_user", | ||
| primaryEmail: environment["CMUX_UITEST_AUTH_EMAIL"] ?? "uitest@cmux.local", | ||
| displayName: environment["CMUX_UITEST_AUTH_NAME"] ?? "UI Test" | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| public enum CMUXAuthMagicLinkCode { | ||
| public static func compose(code: String, nonce: String) -> String { | ||
| code + nonce | ||
| } | ||
| } | ||
|
|
||
| public struct CMUXAuthState: Equatable, Sendable { | ||
| public let isAuthenticated: Bool | ||
| public let currentUser: CMUXAuthUser? | ||
| public let isRestoringSession: Bool | ||
|
|
||
| public init(isAuthenticated: Bool, currentUser: CMUXAuthUser?, isRestoringSession: Bool) { | ||
| self.isAuthenticated = isAuthenticated | ||
| self.currentUser = currentUser | ||
| self.isRestoringSession = isRestoringSession | ||
| } | ||
|
|
||
| public static func primed( | ||
| clearAuthRequested: Bool, | ||
| mockDataEnabled: Bool, | ||
| fixtureUser: CMUXAuthUser?, | ||
| autoLoginCredentials: CMUXAuthAutoLoginCredentials?, | ||
| cachedUser: CMUXAuthUser?, | ||
| hasTokens: Bool, | ||
| mockUser: CMUXAuthUser | ||
| ) -> Self { | ||
| if clearAuthRequested { | ||
| return .cleared() | ||
| } | ||
|
|
||
| if mockDataEnabled { | ||
| return Self(isAuthenticated: true, currentUser: mockUser, isRestoringSession: false) | ||
| } | ||
|
|
||
| if let fixtureUser { | ||
| return Self(isAuthenticated: true, currentUser: fixtureUser, isRestoringSession: false) | ||
| } | ||
|
|
||
| if autoLoginCredentials != nil { | ||
| return Self(isAuthenticated: true, currentUser: cachedUser, isRestoringSession: false) | ||
| } | ||
|
|
||
| return Self( | ||
| isAuthenticated: hasTokens, | ||
| currentUser: cachedUser, | ||
| isRestoringSession: false | ||
| ) | ||
| } | ||
|
|
||
| public static func cleared() -> Self { | ||
| Self(isAuthenticated: false, currentUser: nil, isRestoringSession: false) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import Foundation | ||
|
|
||
| public struct CMUXAuthUser: Codable, Equatable, Sendable { | ||
| public let id: String | ||
| public let primaryEmail: String? | ||
| public let displayName: String? | ||
|
|
||
| public init(id: String, primaryEmail: String?, displayName: String?) { | ||
| self.id = id | ||
| self.primaryEmail = primaryEmail | ||
| self.displayName = displayName | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Use an exact version check for
zig version; the current prefix grep can accept unintended versions.Prompt for AI agents