| 55 | 55 | | Sha256::digest(token.as_bytes())[..8].iter().map(|byte| format!("{byte:02x}")).collect() |
| 56 | 56 | | } |
| 57 | 57 | | |
| 58 | | − | /// The bearer token of an `Authorization` header, if it has one. |
| 58 | + | /// The access token of an `Authorization` header, if it has one: `Bearer |
| 59 | + | /// <token>`, or `token <token>`, the form GitHub also takes and Octokit |
| 60 | + | /// (`@actions/github`, so `actions/checkout` and `actions/github-script`) |
| 61 | + | /// sends. |
| 59 | 62 | | pub fn bearer(header: &str) -> Option<&str> { |
| 60 | 63 | | match header.split_once(' ') { |
| 61 | | − | Some((scheme, token)) if scheme.eq_ignore_ascii_case("bearer") => Some(token.trim()).filter(|t| !t.is_empty()), |
| 64 | + | Some((scheme, token)) if scheme.eq_ignore_ascii_case("bearer") || scheme.eq_ignore_ascii_case("token") => { |
| 65 | + | Some(token.trim()).filter(|t| !t.is_empty()) |
| 66 | + | } |
| 62 | 67 | | _ => None, |
| 63 | 68 | | } |
| 64 | 69 | | } |
| ⋯ |
| 133 | 138 | | } |
| 134 | 139 | | |
| 135 | 140 | | #[test] |
| 136 | | − | fn only_bearer_tokens_are_read() { |
| 141 | + | fn bearer_and_token_schemes_are_read() { |
| 137 | 142 | | assert_eq!(bearer("Bearer g1t_abc "), Some("g1t_abc")); |
| 138 | 143 | | assert_eq!(bearer("bearer g1t_abc"), Some("g1t_abc")); |
| 144 | + | // Octokit's form, as `actions/checkout` sends it for a default branch. |
| 145 | + | assert_eq!(bearer("token g1t_abc"), Some("g1t_abc")); |
| 146 | + | assert_eq!(bearer("Token g1t_abc"), Some("g1t_abc")); |
| 147 | + | assert_eq!(bearer("token "), None); |
| 139 | 148 | | assert_eq!(bearer("Basic dXNlcjpwYXNz"), None); |
| 140 | 149 | | assert_eq!(bearer("Bearer "), None); |
| 141 | 150 | | assert_eq!(bearer(""), None); |