clawdex-mobile 5.1.3-internal.4 → 5.1.3-internal.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/services/rust-bridge/Cargo.lock +1 -1
- package/services/rust-bridge/Cargo.toml +1 -1
- package/services/rust-bridge/src/main.rs +122 -45
- package/vendor/bridge-binaries/darwin-arm64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/darwin-x64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/linux-arm64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/linux-armv7l/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/linux-x64/codex-rust-bridge +0 -0
- package/vendor/bridge-binaries/win32-x64/codex-rust-bridge.exe +0 -0
package/package.json
CHANGED
|
@@ -388,42 +388,91 @@ struct GitHubViewer {
|
|
|
388
388
|
scopes: Vec<String>,
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
#[derive(Debug, Clone)]
|
|
392
|
+
struct ResolvedGitHubAuthGrant {
|
|
393
|
+
access_token: String,
|
|
394
|
+
repositories: Vec<String>,
|
|
395
|
+
}
|
|
396
|
+
|
|
391
397
|
async fn install_github_git_auth(
|
|
392
398
|
state: &Arc<AppState>,
|
|
393
|
-
|
|
394
|
-
repositories: &[String],
|
|
399
|
+
request: GitHubAuthInstallRequest,
|
|
395
400
|
) -> Result<GitHubAuthInstallResponse, BridgeError> {
|
|
396
|
-
let
|
|
397
|
-
if
|
|
398
|
-
return Err(BridgeError::
|
|
399
|
-
"
|
|
400
|
-
"GitHub repository access is required. Sign in again from the app and approve the required repository access.",
|
|
401
|
+
let resolved_grants = resolve_github_auth_grants(request)?;
|
|
402
|
+
if resolved_grants.is_empty() {
|
|
403
|
+
return Err(BridgeError::invalid_params(
|
|
404
|
+
"At least one GitHub auth grant is required",
|
|
401
405
|
));
|
|
402
406
|
}
|
|
403
407
|
|
|
404
|
-
let
|
|
408
|
+
let mut login = None;
|
|
409
|
+
let mut scopes = Vec::new();
|
|
410
|
+
if let Some(first_grant) = resolved_grants.first() {
|
|
411
|
+
if let Ok(viewer) = fetch_github_viewer(state, &first_grant.access_token).await {
|
|
412
|
+
if !github_token_can_be_used_for_git_auth(&viewer.scopes) {
|
|
413
|
+
return Err(BridgeError::forbidden(
|
|
414
|
+
"github_repo_scope_required",
|
|
415
|
+
"GitHub repository access is required. Sign in again from the app and approve the required repository access.",
|
|
416
|
+
));
|
|
417
|
+
}
|
|
418
|
+
login = Some(viewer.login);
|
|
419
|
+
scopes = viewer.scopes;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
405
423
|
let credentials_file = resolve_github_credentials_file_path()?;
|
|
406
424
|
let git_config_file = resolve_github_git_config_file_path()?;
|
|
407
425
|
ensure_private_parent_dir(&credentials_file).await?;
|
|
408
|
-
write_github_credentials_file(&credentials_file,
|
|
409
|
-
|
|
410
|
-
write_github_git_config_file(
|
|
411
|
-
&git_config_file,
|
|
412
|
-
&credentials_file,
|
|
413
|
-
&normalized_repositories,
|
|
414
|
-
)
|
|
415
|
-
.await?;
|
|
426
|
+
write_github_credentials_file(&credentials_file, &resolved_grants).await?;
|
|
427
|
+
write_github_git_config_file(&git_config_file, &credentials_file, &resolved_grants).await?;
|
|
416
428
|
configure_git_credential_store(state, &credentials_file, &git_config_file).await?;
|
|
417
429
|
|
|
418
430
|
Ok(GitHubAuthInstallResponse {
|
|
419
431
|
installed: true,
|
|
420
432
|
host: GITHUB_HOST.to_string(),
|
|
421
|
-
login
|
|
422
|
-
scopes
|
|
433
|
+
login,
|
|
434
|
+
scopes,
|
|
423
435
|
credential_file: credentials_file.to_string_lossy().to_string(),
|
|
436
|
+
grants_installed: resolved_grants.len(),
|
|
424
437
|
})
|
|
425
438
|
}
|
|
426
439
|
|
|
440
|
+
fn resolve_github_auth_grants(
|
|
441
|
+
request: GitHubAuthInstallRequest,
|
|
442
|
+
) -> Result<Vec<ResolvedGitHubAuthGrant>, BridgeError> {
|
|
443
|
+
let raw_grants = if let Some(grants) = request.grants {
|
|
444
|
+
grants
|
|
445
|
+
} else if let Some(access_token) = request.access_token {
|
|
446
|
+
vec![GitHubAuthGrantInput {
|
|
447
|
+
access_token,
|
|
448
|
+
repositories: request.repositories,
|
|
449
|
+
}]
|
|
450
|
+
} else {
|
|
451
|
+
Vec::new()
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
let mut grants = Vec::new();
|
|
455
|
+
for grant in raw_grants {
|
|
456
|
+
let access_token = grant.access_token.trim().to_string();
|
|
457
|
+
if access_token.is_empty() {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
let repositories =
|
|
462
|
+
normalize_github_auth_repositories(grant.repositories.as_deref().unwrap_or(&[]));
|
|
463
|
+
if repositories.is_empty() {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
grants.push(ResolvedGitHubAuthGrant {
|
|
468
|
+
access_token,
|
|
469
|
+
repositories,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
Ok(grants)
|
|
474
|
+
}
|
|
475
|
+
|
|
427
476
|
async fn fetch_github_viewer(
|
|
428
477
|
state: &Arc<AppState>,
|
|
429
478
|
access_token: &str,
|
|
@@ -565,18 +614,20 @@ async fn ensure_private_parent_dir(path: &Path) -> Result<(), BridgeError> {
|
|
|
565
614
|
|
|
566
615
|
async fn write_github_credentials_file(
|
|
567
616
|
credentials_file: &Path,
|
|
568
|
-
|
|
569
|
-
repositories: &[String],
|
|
617
|
+
grants: &[ResolvedGitHubAuthGrant],
|
|
570
618
|
) -> Result<(), BridgeError> {
|
|
571
619
|
let mut content = String::new();
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
620
|
+
for grant in grants {
|
|
621
|
+
for repository in &grant.repositories {
|
|
622
|
+
content.push_str(&format!(
|
|
623
|
+
"https://x-access-token:{}@{GITHUB_HOST}/{repository}\n",
|
|
624
|
+
grant.access_token
|
|
625
|
+
));
|
|
626
|
+
content.push_str(&format!(
|
|
627
|
+
"https://x-access-token:{}@{GITHUB_HOST}/{repository}.git\n",
|
|
628
|
+
grant.access_token
|
|
629
|
+
));
|
|
630
|
+
}
|
|
580
631
|
}
|
|
581
632
|
|
|
582
633
|
fs::write(credentials_file, content)
|
|
@@ -600,21 +651,23 @@ async fn write_github_credentials_file(
|
|
|
600
651
|
async fn write_github_git_config_file(
|
|
601
652
|
git_config_file: &Path,
|
|
602
653
|
credentials_file: &Path,
|
|
603
|
-
|
|
654
|
+
grants: &[ResolvedGitHubAuthGrant],
|
|
604
655
|
) -> Result<(), BridgeError> {
|
|
605
656
|
let helper_value = format!("store --file {}", credentials_file.to_string_lossy());
|
|
606
657
|
let mut content = String::from(
|
|
607
658
|
"[credential \"https://github.com\"]\n\tuseHttpPath = true\n[url \"https://github.com/\"]\n\tinsteadOf = git@github.com:\n\tinsteadOf = ssh://git@github.com/\n",
|
|
608
659
|
);
|
|
609
660
|
|
|
610
|
-
for
|
|
611
|
-
for
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
661
|
+
for grant in grants {
|
|
662
|
+
for repository in &grant.repositories {
|
|
663
|
+
for context in [
|
|
664
|
+
format!("https://{GITHUB_HOST}/{repository}"),
|
|
665
|
+
format!("https://{GITHUB_HOST}/{repository}.git"),
|
|
666
|
+
] {
|
|
667
|
+
content.push_str(&format!(
|
|
668
|
+
"[credential \"{context}\"]\n\thelper =\n\thelper = {helper_value}\n\tusername = x-access-token\n"
|
|
669
|
+
));
|
|
670
|
+
}
|
|
618
671
|
}
|
|
619
672
|
}
|
|
620
673
|
|
|
@@ -785,7 +838,9 @@ impl AppState {
|
|
|
785
838
|
let Some(service) = &self.github_codespaces_auth else {
|
|
786
839
|
return false;
|
|
787
840
|
};
|
|
788
|
-
let Some(token) =
|
|
841
|
+
let Some(token) =
|
|
842
|
+
extract_auth_token(headers, query_token, self.config.allow_query_token_auth)
|
|
843
|
+
else {
|
|
789
844
|
return false;
|
|
790
845
|
};
|
|
791
846
|
|
|
@@ -793,6 +848,24 @@ impl AppState {
|
|
|
793
848
|
}
|
|
794
849
|
}
|
|
795
850
|
|
|
851
|
+
fn extract_auth_token<'a>(
|
|
852
|
+
headers: &'a HeaderMap,
|
|
853
|
+
query_token: Option<&'a str>,
|
|
854
|
+
allow_query_token_auth: bool,
|
|
855
|
+
) -> Option<&'a str> {
|
|
856
|
+
if let Some(token) = extract_bearer_token(headers) {
|
|
857
|
+
return Some(token);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if allow_query_token_auth {
|
|
861
|
+
if let Some(token) = query_token.map(str::trim).filter(|token| !token.is_empty()) {
|
|
862
|
+
return Some(token);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
None
|
|
867
|
+
}
|
|
868
|
+
|
|
796
869
|
#[derive(Debug, Clone, Serialize)]
|
|
797
870
|
#[serde(rename_all = "camelCase")]
|
|
798
871
|
struct BrowserPreviewSessionResponse {
|
|
@@ -5549,6 +5622,14 @@ struct GitQueryRequest {
|
|
|
5549
5622
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
5550
5623
|
#[serde(rename_all = "camelCase")]
|
|
5551
5624
|
struct GitHubAuthInstallRequest {
|
|
5625
|
+
access_token: Option<String>,
|
|
5626
|
+
repositories: Option<Vec<String>>,
|
|
5627
|
+
grants: Option<Vec<GitHubAuthGrantInput>>,
|
|
5628
|
+
}
|
|
5629
|
+
|
|
5630
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
5631
|
+
#[serde(rename_all = "camelCase")]
|
|
5632
|
+
struct GitHubAuthGrantInput {
|
|
5552
5633
|
access_token: String,
|
|
5553
5634
|
repositories: Option<Vec<String>>,
|
|
5554
5635
|
}
|
|
@@ -5558,9 +5639,10 @@ struct GitHubAuthInstallRequest {
|
|
|
5558
5639
|
struct GitHubAuthInstallResponse {
|
|
5559
5640
|
installed: bool,
|
|
5560
5641
|
host: String,
|
|
5561
|
-
login: String
|
|
5642
|
+
login: Option<String>,
|
|
5562
5643
|
scopes: Vec<String>,
|
|
5563
5644
|
credential_file: String,
|
|
5645
|
+
grants_installed: usize,
|
|
5564
5646
|
}
|
|
5565
5647
|
|
|
5566
5648
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
@@ -6923,12 +7005,7 @@ async fn handle_bridge_method(
|
|
|
6923
7005
|
let request: GitHubAuthInstallRequest =
|
|
6924
7006
|
serde_json::from_value(params.unwrap_or_else(|| json!({})))
|
|
6925
7007
|
.map_err(|error| BridgeError::invalid_params(&error.to_string()))?;
|
|
6926
|
-
let result = install_github_git_auth(
|
|
6927
|
-
state,
|
|
6928
|
-
&request.access_token,
|
|
6929
|
-
request.repositories.as_deref().unwrap_or(&[]),
|
|
6930
|
-
)
|
|
6931
|
-
.await?;
|
|
7008
|
+
let result = install_github_git_auth(state, request).await?;
|
|
6932
7009
|
serde_json::to_value(result).map_err(|error| BridgeError::server(&error.to_string()))
|
|
6933
7010
|
}
|
|
6934
7011
|
"bridge/attachments/upload" => {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|