Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3,184 changes: 1,563 additions & 1,621 deletions Cargo.lock

Large diffs are not rendered by default.

87 changes: 49 additions & 38 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ anyhow = "1"
base64 = "0.21"
bytes = "1"
chrono = { version = "0.4", features = ["serde"] }
oauth2 = "4.4.1"
# `default-features = false` leaves out oauth2's own reqwest client; the flows
# go through `util::oauth2_http_request` on the app's reqwest instead.
oauth2 = { version = "5", default-features = false }
futures = "0.3"
hyper = { version = "0.14", features = [
"http1",
Expand All @@ -38,13 +40,20 @@ sha2 = "0.10.7"
crc32fast = "1.3.2"
routerify = "3"
routerify-query = "3"
reqwest = { version = "0.11.18", default-features = false, features = [
"rustls-tls",
"stream",
# rust-s3 has its own reqwest (0.12) with no `gzip`/`brotli`, and that must
# stay so: reqwest transparently decodes `Content-Encoding: gzip` responses
# when those features are on, and objects we store gzip-encoded (tarballs,
# docs) would then come back from the bucket already inflated. Keep every
# other reqwest user on this version so the features do not unify into it.
reqwest = { version = "0.13", default-features = false, features = [
"rustls",
"http2",
"gzip",
"brotli",
"json",
"multipart",
"form",
# For the OTLP exporters' client, see `tracing.rs`.
"blocking",
] }
rmp-serde = "1"
serde = { version = "1", features = ["derive"] }
Expand All @@ -67,33 +76,32 @@ const_format = { version = "0.2", features = ["const_generics"] }
tar = "0.4"
tracing = "0.1"
tracing-futures = "0.2"
tracing-opentelemetry = "0.28"
tracing-opentelemetry = "0.33"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
opentelemetry = { version = "0.27", features = ["trace", "logs"] }
opentelemetry_sdk = { version = "0.27", features = [
"rt-tokio",
"trace",
"logs",
] }
opentelemetry = { version = "0.32", features = ["trace", "logs"] }
opentelemetry_sdk = { version = "0.32.1", features = ["trace", "logs"] }
# Bridges `tracing` events into OpenTelemetry log records so the same logs we
# print to stdout are also exported over OTLP (to Grafana Cloud Loki).
opentelemetry-appender-tracing = "0.27"
opentelemetry-appender-tracing = "0.32"
# OTLP over HTTP/protobuf (not gRPC): the managed Grafana Cloud OTLP gateway only
# speaks OTLP/HTTP. `reqwest-client` routes export through reqwest (its own
# reqwest 0.12, separate from the app's reqwest 0.11). Default `grpc-tonic` is
# off. `http-proto` enables trace+metrics; `logs` is listed explicitly because
# it does not.
opentelemetry-otlp = { version = "0.27", default-features = false, features = [
# speaks OTLP/HTTP. The SDK's batch processors run on their own thread and
# block on the export future, so the exporter needs a blocking HTTP client:
# `reqwest-blocking-client` (shares the app's reqwest 0.13) and
# `reqwest-rustls` for TLS to the https endpoint. Default
# `grpc-tonic` is off. `http-proto` enables trace+metrics; `logs` is listed
# explicitly because it does not.
opentelemetry-otlp = { version = "0.32", default-features = false, features = [
"trace",
"logs",
"http-proto",
"reqwest-client",
"reqwest-blocking-client",
"reqwest-rustls",
] }
rust-s3 = { version = "0.37.1", default-features = false, features = ["tokio-rustls-tls"] }
deno_semver = "0.10.1"
flate2 = "1"
thiserror = "2"
async-tar = "0.4.2"
async-tar = "0.6"
async-compression = { version = "0.4", features = ["futures-io", "gzip"] }
deno_graph = "=0.111.0"
deno_ast = { version = "0.53.0", features = ["view"] }
Expand All @@ -103,35 +111,38 @@ deno_error = "0.7.0"
comrak = { version = "0.29.0", default-features = false }
ammonia = "4.0.0"
async-trait = "0.1.73"
jsonwebkey = { version = "0.3.5", features = ["jsonwebtoken", "jwt-convert"] }
jsonwebtoken = "8.3.0"
jsonwebtoken = { version = "11", features = ["aws_lc_rs"] }
indexmap = { version = "2.13.0", features = ["serde"] }
pin-project = "1.1.3"
regex = "1.10.2"
postmark = { version = "=0.10.0", features = ["reqwest-rustls-tls"] }
postmark = { version = "2", features = ["reqwest-rustls-tls"] }
handlebars = "5.0.0"
jsonc-parser = { version = "0.26.3", features = ["serde"] }
sha1 = "0.10.6"
infer = "0.15.0"
x509-parser = { version = "0.15.1", features = ["verify"] }
x509-parser = { version = "0.18", features = ["verify"] }
sitemap-rs = "0.2.1"
askalono = "0.5.0"
moka = { version = "0.12", features = ["future", "sync"] }

tree-sitter-highlight = "0.22.6"
tree-sitter-javascript = "0.21.4"
tree-sitter-typescript = "0.21.2"
tree-sitter-json = "0.21.0"
tree-sitter-regex = "0.21.0"
tree-sitter-css = "0.21.0"
tree-sitter-md = "0.2.3"
tree-sitter-rust = "0.21.2"
tree-sitter-html = "0.20.3"
tree-sitter-bash = "0.21.0"
tree-sitter-xml = "0.6.4"
tree-sitter-toml-ng = "0.6.0"
tree-sitter-yaml = "0.6.1"
tree-sitter-c = "0.21.4"
# tree-sitter-highlight 0.27 and tree-sitter-language 0.1.8 need rustc 1.90;
# the workspace resolver is not MSRV-aware, so the latter is pinned here
# rather than only in Cargo.lock. Lift both when the toolchain moves.
tree-sitter-highlight = "0.26"
tree-sitter-language = "=0.1.7"
tree-sitter-javascript = "0.25"
tree-sitter-typescript = "0.23"
tree-sitter-json = "0.24"
tree-sitter-regex = "0.25"
tree-sitter-css = "0.25"
tree-sitter-md = "0.5"
tree-sitter-rust = "0.24"
tree-sitter-html = "0.23"
tree-sitter-bash = "0.25"
tree-sitter-xml = "0.7"
tree-sitter-toml-ng = "0.7"
tree-sitter-yaml = "0.7"
tree-sitter-c = "0.24"
lazy_static = "1.5.0"
tikv-jemallocator = { version = "0.6", features = ["profiling"] }
tikv-jemalloc-ctl = { version = "0.6", features = ["stats"] }
Expand Down
45 changes: 4 additions & 41 deletions api/src/api/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,61 +365,24 @@ impl From<serde_json::Error> for ApiError {
}
}

impl From<oauth2::reqwest::Error<reqwest::Error>> for ApiError {
fn from(error: oauth2::reqwest::Error<reqwest::Error>) -> ApiError {
anyhow::Error::from(error).into()
}
}

impl
From<
oauth2::RequestTokenError<
oauth2::reqwest::Error<reqwest::Error>,
reqwest::Error,
oauth2::basic::BasicErrorResponse,
>,
> for ApiError
{
fn from(
error: oauth2::RequestTokenError<
oauth2::reqwest::Error<reqwest::Error>,
reqwest::Error,
oauth2::basic::BasicErrorResponse,
>,
) -> ApiError {
anyhow::Error::from(error).into()
}
}

impl
From<
oauth2::RequestTokenError<
oauth2::reqwest::Error<reqwest::Error>,
oauth2::DeviceCodeErrorResponse,
>,
> for ApiError
{
fn from(
error: oauth2::RequestTokenError<
oauth2::reqwest::Error<reqwest::Error>,
oauth2::DeviceCodeErrorResponse,
>,
) -> ApiError {
anyhow::Error::from(error).into()
}
}

impl From<oauth2::RequestTokenError<ApiError, oauth2::DeviceCodeErrorResponse>>
for ApiError
{
fn from(
error: oauth2::RequestTokenError<ApiError, oauth2::DeviceCodeErrorResponse>,
) -> ApiError {
match error {
oauth2::RequestTokenError::Request(e) => e,
e => anyhow::Error::from(e).into(),
}
}
}

impl From<oauth2::ConfigurationError> for ApiError {
fn from(error: oauth2::ConfigurationError) -> ApiError {
anyhow::Error::from(error).into()
Expand All @@ -429,14 +392,14 @@ impl From<oauth2::ConfigurationError> for ApiError {
impl
From<
oauth2::RequestTokenError<
oauth2::reqwest::Error<reqwest::Error>,
reqwest::Error,
oauth2::basic::BasicRevocationErrorResponse,
>,
> for ApiError
{
fn from(
error: oauth2::RequestTokenError<
oauth2::reqwest::Error<reqwest::Error>,
reqwest::Error,
oauth2::basic::BasicRevocationErrorResponse,
>,
) -> ApiError {
Expand Down
63 changes: 35 additions & 28 deletions api/src/auth/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
use crate::api::ApiError;
use crate::db::*;
use crate::util::ApiResult;
use crate::util::oauth2_http_request;
use chrono::DateTime;
use chrono::Duration;
use chrono::Utc;
use oauth2::EndpointNotSet;
use oauth2::EndpointSet;
use oauth2::ExtraTokenFields;
use oauth2::RedirectUrl;
use oauth2::StandardRevocableToken;
Expand All @@ -15,7 +18,6 @@ use oauth2::TokenResponse;
use oauth2::basic::BasicErrorResponse;
use oauth2::basic::BasicRevocationErrorResponse;
use oauth2::basic::BasicTokenType;
use oauth2::reqwest::async_http_client;
use serde::Deserialize;
use serde::Serialize;
use tracing::instrument;
Expand All @@ -30,42 +32,47 @@ impl ExtraTokenFields for GithubTokenExtraFields {}
type GithubTokenResponse =
StandardTokenResponse<GithubTokenExtraFields, BasicTokenType>;

/// An `oauth2::Client` with the authorization and token endpoints set, and
/// no device authorization, introspection, or revocation endpoint.
type GithubClient = oauth2::Client<
BasicErrorResponse,
GithubTokenResponse,
StandardTokenIntrospectionResponse<GithubTokenExtraFields, BasicTokenType>,
StandardRevocableToken,
BasicRevocationErrorResponse,
EndpointSet,
EndpointNotSet,
EndpointNotSet,
EndpointNotSet,
EndpointSet,
>;

#[derive(Clone)]
pub struct Oauth2Client(
pub oauth2::Client<
BasicErrorResponse,
GithubTokenResponse,
BasicTokenType,
StandardTokenIntrospectionResponse<GithubTokenExtraFields, BasicTokenType>,
StandardRevocableToken,
BasicRevocationErrorResponse,
>,
pub String,
);
pub struct Oauth2Client(pub GithubClient, pub String);

impl Oauth2Client {
pub fn new(registry_url: &Url, id: String, secret: String) -> Self {
Self(
oauth2::Client::new(
oauth2::ClientId::new(id),
Some(oauth2::ClientSecret::new(secret.clone())),
oauth2::AuthUrl::new(
"https://github.com/login/oauth/authorize".to_string(),
oauth2::Client::new(oauth2::ClientId::new(id))
.set_client_secret(oauth2::ClientSecret::new(secret.clone()))
.set_auth_uri(
oauth2::AuthUrl::new(
"https://github.com/login/oauth/authorize".to_string(),
)
.unwrap(),
)
.unwrap(),
Some(
.set_token_uri(
oauth2::TokenUrl::new(
"https://github.com/login/oauth/access_token".to_string(),
)
.unwrap(),
),
)
.set_redirect_uri(RedirectUrl::from_url(
Url::options()
.base_url(Some(registry_url))
.parse("./login/callback/github")
.unwrap(),
)),
)
.set_redirect_uri(RedirectUrl::from_url(
Url::options()
.base_url(Some(registry_url))
.parse("./login/callback/github")
.unwrap(),
)),
secret,
)
}
Expand Down Expand Up @@ -127,7 +134,7 @@ pub async fn access_token(
.exchange_refresh_token(&oauth2::RefreshToken::new(
ghid.refresh_token.clone().unwrap(),
))
.request_async(async_http_client)
.request_async(&oauth2_http_request)
.await?;
let new_github_identity = new_github_identity_from_oauth_response(res);
ghid.access_token = new_github_identity.access_token;
Expand Down
Loading
Loading