Skip to content

Commit 9d0f916

Browse files
authored
Merge pull request #6315 from Turbo87/returned-token-scopes
PUT /me/tokens: Return `crate_scopes` and `endpoint_scopes` fields too
2 parents a4c94a7 + 0c180e5 commit 9d0f916

7 files changed

+95
-26
lines changed

src/models/token.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ mod tests {
154154
.and_hms_opt(14, 23, 12),
155155
)
156156
.unwrap(),
157+
crate_scopes: None,
158+
endpoint_scopes: None,
157159
};
158160
let json = serde_json::to_string(&tok).unwrap();
159161
assert_some!(json

src/tests/routes/me/tokens/create.rs

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1+
use crate::util::insta::{self, assert_yaml_snapshot};
12
use crate::util::{RequestHelper, TestApp};
23
use cargo_registry::models::token::{CrateScope, EndpointScope};
34
use cargo_registry::models::ApiToken;
4-
use cargo_registry::views::EncodableApiTokenWithToken;
55
use diesel::prelude::*;
66
use http::StatusCode;
7+
use serde_json::Value;
78

89
static NEW_BAR: &[u8] = br#"{ "api_token": { "name": "bar" } }"#;
910

10-
#[derive(Deserialize)]
11-
struct NewResponse {
12-
api_token: EncodableApiTokenWithToken,
13-
}
14-
1511
#[test]
1612
fn create_token_logged_out() {
1713
let (_, anon) = TestApp::init().empty();
@@ -63,9 +59,14 @@ fn create_token_exceeded_tokens_per_user() {
6359
fn create_token_success() {
6460
let (app, _, user) = TestApp::init().with_user();
6561

66-
let json: NewResponse = user.put("/api/v1/me/tokens", NEW_BAR).good();
67-
assert_eq!(json.api_token.name, "bar");
68-
assert!(!json.api_token.token.is_empty());
62+
let response = user.put::<()>("/api/v1/me/tokens", NEW_BAR);
63+
assert_eq!(response.status(), StatusCode::OK);
64+
assert_yaml_snapshot!(response.into_json(), {
65+
".api_token.id" => insta::any_id_redaction(),
66+
".api_token.created_at" => "[datetime]",
67+
".api_token.last_used_at" => "[datetime]",
68+
".api_token.token" => insta::api_token_redaction(),
69+
});
6970

7071
let tokens: Vec<ApiToken> =
7172
app.db(|conn| assert_ok!(ApiToken::belonging_to(user.as_model()).load(conn)));
@@ -80,21 +81,22 @@ fn create_token_success() {
8081
#[test]
8182
fn create_token_multiple_have_different_values() {
8283
let (_, _, user) = TestApp::init().with_user();
83-
let first: NewResponse = user.put("/api/v1/me/tokens", NEW_BAR).good();
84-
let second: NewResponse = user.put("/api/v1/me/tokens", NEW_BAR).good();
84+
let first: Value = user.put("/api/v1/me/tokens", NEW_BAR).good();
85+
let second: Value = user.put("/api/v1/me/tokens", NEW_BAR).good();
8586

86-
assert_ne!(first.api_token.token, second.api_token.token);
87+
assert_eq!(first["api_token"]["name"], second["api_token"]["name"]);
88+
assert_ne!(first["api_token"]["token"], second["api_token"]["token"]);
8789
}
8890

8991
#[test]
9092
fn create_token_multiple_users_have_different_values() {
9193
let (app, _, user1) = TestApp::init().with_user();
92-
let first_token: NewResponse = user1.put("/api/v1/me/tokens", NEW_BAR).good();
94+
let first: Value = user1.put("/api/v1/me/tokens", NEW_BAR).good();
9395

9496
let user2 = app.db_new_user("bar");
95-
let second_token: NewResponse = user2.put("/api/v1/me/tokens", NEW_BAR).good();
97+
let second: Value = user2.put("/api/v1/me/tokens", NEW_BAR).good();
9698

97-
assert_ne!(first_token.api_token.token, second_token.api_token.token);
99+
assert_ne!(first["api_token"]["token"], second["api_token"]["token"]);
98100
}
99101

100102
#[test]
@@ -123,11 +125,14 @@ fn create_token_with_scopes() {
123125
}
124126
});
125127

126-
let json: NewResponse = user
127-
.put("/api/v1/me/tokens", &serde_json::to_vec(&json).unwrap())
128-
.good();
129-
assert_eq!(json.api_token.name, "bar");
130-
assert!(!json.api_token.token.is_empty());
128+
let response = user.put::<()>("/api/v1/me/tokens", &serde_json::to_vec(&json).unwrap());
129+
assert_eq!(response.status(), StatusCode::OK);
130+
assert_yaml_snapshot!(response.into_json(), {
131+
".api_token.id" => insta::any_id_redaction(),
132+
".api_token.created_at" => "[datetime]",
133+
".api_token.last_used_at" => "[datetime]",
134+
".api_token.token" => insta::api_token_redaction(),
135+
});
131136

132137
let tokens: Vec<ApiToken> =
133138
app.db(|conn| assert_ok!(ApiToken::belonging_to(user.as_model()).load(conn)));
@@ -160,11 +165,14 @@ fn create_token_with_null_scopes() {
160165
}
161166
});
162167

163-
let json: NewResponse = user
164-
.put("/api/v1/me/tokens", &serde_json::to_vec(&json).unwrap())
165-
.good();
166-
assert_eq!(json.api_token.name, "bar");
167-
assert!(!json.api_token.token.is_empty());
168+
let response = user.put::<()>("/api/v1/me/tokens", &serde_json::to_vec(&json).unwrap());
169+
assert_eq!(response.status(), StatusCode::OK);
170+
assert_yaml_snapshot!(response.into_json(), {
171+
".api_token.id" => insta::any_id_redaction(),
172+
".api_token.created_at" => "[datetime]",
173+
".api_token.last_used_at" => "[datetime]",
174+
".api_token.token" => insta::api_token_redaction(),
175+
});
168176

169177
let tokens: Vec<ApiToken> =
170178
app.db(|conn| assert_ok!(ApiToken::belonging_to(user.as_model()).load(conn)));
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
source: src/tests/routes/me/tokens/create.rs
3+
expression: response.into_json()
4+
---
5+
api_token:
6+
crate_scopes: ~
7+
created_at: "[datetime]"
8+
endpoint_scopes: ~
9+
id: "[id]"
10+
last_used_at: "[datetime]"
11+
name: bar
12+
revoked: false
13+
token: "[token]"
14+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
source: src/tests/routes/me/tokens/create.rs
3+
expression: response.into_json()
4+
---
5+
api_token:
6+
crate_scopes: ~
7+
created_at: "[datetime]"
8+
endpoint_scopes: ~
9+
id: "[id]"
10+
last_used_at: "[datetime]"
11+
name: bar
12+
revoked: false
13+
token: "[token]"
14+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
source: src/tests/routes/me/tokens/create.rs
3+
expression: response.into_json()
4+
---
5+
api_token:
6+
crate_scopes:
7+
- tokio
8+
- tokio-*
9+
created_at: "[datetime]"
10+
endpoint_scopes:
11+
- publish-update
12+
id: "[id]"
13+
last_used_at: "[datetime]"
14+
name: bar
15+
revoked: false
16+
token: "[token]"
17+

src/tests/util/insta.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,10 @@ pub fn any_id_redaction() -> insta::internals::Redaction {
1313
"[id]"
1414
})
1515
}
16+
17+
pub fn api_token_redaction() -> insta::internals::Redaction {
18+
insta::dynamic_redaction(move |value, _path| {
19+
assert!(assert_some!(value.as_str()).starts_with("cio"));
20+
"[token]"
21+
})
22+
}

src/views.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use chrono::NaiveDateTime;
22
use url::Url;
33

44
use crate::github;
5+
use crate::models::token::{CrateScope, EndpointScope};
56
use crate::models::{
67
Category, Crate, CrateOwnerInvitation, CreatedApiToken, Dependency, DependencyKind, Keyword,
78
Owner, ReverseDependency, Team, TopVersions, User, Version, VersionDownload,
@@ -467,7 +468,7 @@ impl From<Team> for EncodableTeam {
467468
/// The serialization format for the `ApiToken` model with its token value.
468469
/// This should only be used when initially creating a new token to minimize
469470
/// the chance of token leaks.
470-
#[derive(Deserialize, Serialize, Debug)]
471+
#[derive(Serialize, Debug)]
471472
pub struct EncodableApiTokenWithToken {
472473
pub id: i32,
473474
pub name: String,
@@ -477,6 +478,10 @@ pub struct EncodableApiTokenWithToken {
477478
pub created_at: NaiveDateTime,
478479
#[serde(with = "rfc3339::option")]
479480
pub last_used_at: Option<NaiveDateTime>,
481+
/// `None` or a list of crate scope patterns (see RFC #2947)
482+
pub crate_scopes: Option<Vec<CrateScope>>,
483+
/// A list of endpoint scopes or `None` for the `legacy` endpoint scope (see RFC #2947)
484+
pub endpoint_scopes: Option<Vec<EndpointScope>>,
480485
}
481486

482487
impl From<CreatedApiToken> for EncodableApiTokenWithToken {
@@ -488,6 +493,8 @@ impl From<CreatedApiToken> for EncodableApiTokenWithToken {
488493
revoked: token.model.revoked,
489494
created_at: token.model.created_at,
490495
last_used_at: token.model.last_used_at,
496+
crate_scopes: token.model.crate_scopes,
497+
endpoint_scopes: token.model.endpoint_scopes,
491498
}
492499
}
493500
}

0 commit comments

Comments
 (0)