Skip to content

Commit aa29477

Browse files
Prefer --url argument over empty auth token URL (#1914)
With this change, the CLI will treat an org auth token that specifies an empty URL the same way as an org auth token that is not specifying a URL at all. We implemented this change in behavior by changing the type of the url in the AuthTokenPayload from an Option<String> to a String. In cases where the url previously would have been set to None, the url will now be set to an empty string. Uses of the AuthTokenPayload's url field have been updated to treat empty strings the way they previously treated None values. Fixes GH-1913
1 parent c2bb14c commit aa29477

File tree

5 files changed

+51
-28
lines changed

5 files changed

+51
-28
lines changed

src/config.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,20 @@ impl Config {
6060
_ => None, // get_default_auth never returns Auth::Token variant
6161
};
6262

63-
let mut url = get_default_url(&ini);
64-
65-
if let Some(token_url) = token_embedded_data.as_ref().and_then(|td| td.url.as_ref()) {
66-
if url == DEFAULT_URL || url.is_empty() {
67-
url = token_url.clone();
68-
} else if url != *token_url {
69-
bail!(
70-
"Two different url values supplied: `{}` (from token), `{url}`.",
71-
token_url,
72-
);
73-
}
74-
}
63+
let default_url = get_default_url(&ini);
64+
let token_url = token_embedded_data
65+
.as_ref()
66+
.map(|td| td.url.as_str())
67+
.unwrap_or_default();
68+
69+
let url = match (default_url.as_str(), token_url) {
70+
(_, "") => default_url,
71+
_ if default_url == token_url => default_url,
72+
(DEFAULT_URL | "", _) => String::from(token_url),
73+
_ => bail!(
74+
"Two different url values supplied: `{token_url}` (from token), `{default_url}`."
75+
),
76+
};
7577

7678
Ok(Config {
7779
filename,
@@ -171,12 +173,8 @@ impl Config {
171173
Some(Auth::Token(ref val)) => {
172174
self.cached_token_data = val.payload().cloned();
173175

174-
if let Some(token_url) = self
175-
.cached_token_data
176-
.as_ref()
177-
.and_then(|td| td.url.as_ref())
178-
{
179-
self.cached_base_url = token_url.clone();
176+
if let Some(token_url) = self.cached_token_data.as_ref().map(|td| td.url.as_str()) {
177+
self.cached_base_url = token_url.to_string();
180178
}
181179

182180
self.ini
@@ -206,15 +204,16 @@ impl Config {
206204

207205
/// Sets the URL
208206
pub fn set_base_url(&mut self, url: &str) -> Result<()> {
209-
if let Some(token_url) = self
207+
let token_url = self
210208
.cached_token_data
211209
.as_ref()
212-
.and_then(|td| td.url.as_ref())
213-
{
214-
if url != token_url {
215-
bail!("Two different url values supplied: `{token_url}` (from token), `{url}`.");
216-
}
210+
.map(|td| td.url.as_str())
211+
.unwrap_or_default();
212+
213+
if !token_url.is_empty() && url != token_url {
214+
bail!("Two different url values supplied: `{token_url}` (from token), `{url}`.");
217215
}
216+
218217
self.cached_base_url = url.to_owned();
219218
self.ini
220219
.set_to(Some("defaults"), "url".into(), self.cached_base_url.clone());

src/utils/auth_token/org_auth_token.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{AuthTokenParseError, Result};
2-
use serde::Deserialize;
2+
use serde::{Deserialize, Deserializer};
33

44
const ORG_AUTH_TOKEN_PREFIX: &str = "sntrys_";
55
const ORG_TOKEN_SECRET_BYTES: usize = 32;
@@ -16,9 +16,20 @@ pub struct OrgAuthToken {
1616
#[allow(dead_code)] // Otherwise, we get a warning about unused fields
1717
pub struct AuthTokenPayload {
1818
iat: f64,
19-
pub url: Option<String>, // URL may be missing from some old auth tokens, see getsentry/sentry#57123
2019
region_url: String,
2120
pub org: String,
21+
22+
// URL may be missing from some old auth tokens, see getsentry/sentry#57123
23+
#[serde(deserialize_with = "url_deserializer")]
24+
pub url: String,
25+
}
26+
27+
/// Deserializes a URL from a string, returning an empty string if the URL is missing or null.
28+
fn url_deserializer<'de, D>(deserializer: D) -> std::result::Result<String, D::Error>
29+
where
30+
D: Deserializer<'de>,
31+
{
32+
Option::deserialize(deserializer).map(|url| url.unwrap_or_default())
2233
}
2334

2435
impl OrgAuthToken {

src/utils/auth_token/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ fn test_valid_org_auth_token() {
3333

3434
let payload = token.payload().unwrap();
3535
assert_eq!(payload.org, "sentry");
36-
assert_eq!(payload.url, Some(String::from("http://localhost:8000")));
36+
assert_eq!(payload.url, "http://localhost:8000");
3737

3838
assert_eq!(good_token, token.to_string());
3939

@@ -56,7 +56,7 @@ fn test_valid_org_auth_token_missing_url() {
5656

5757
let payload = token.payload().unwrap();
5858
assert_eq!(payload.org, "sentry");
59-
assert!(payload.url.is_none());
59+
assert!(payload.url.is_empty());
6060

6161
assert_eq!(good_token, token.to_string());
6262

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
This auth token has an empty URL. We expect the --url argument to take precedence here
2+
```
3+
$ sentry-cli --auth-token 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 --url https://sentry.example.com info
4+
? failed
5+
Sentry Server: https://sentry.example.com
6+
...
7+
8+
```

tests/integration/org_tokens.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ fn org_token_org_match() {
2424
fn org_token_url_works() {
2525
register_test("org_tokens/url-works.trycmd");
2626
}
27+
28+
#[test]
29+
fn org_token_url_mismatch_empty_token() {
30+
register_test("org_tokens/url-mismatch-empty-token.trycmd");
31+
}

0 commit comments

Comments
 (0)