use super::TokenKind;
#[must_use]
pub fn detect(token: &str) -> Option<TokenKind> {
if is_private_key_header(token) {
return Some(TokenKind::PrivateKey);
}
let alnum = |text: &str| text.bytes().all(|b| b.is_ascii_alphanumeric());
let after = |prefix: &str| token.strip_prefix(prefix);
if let Some(body) = ["ghp_", "gho_", "ghu_", "ghs_", "ghr_"]
.iter()
.find_map(|p| after(p))
{
if body.len() == 36 && alnum(body) {
return Some(TokenKind::GitHub);
}
}
if let Some(body) = after("github_pat_") {
if body.len() >= 22 && body.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_') {
return Some(TokenKind::GitHub);
}
}
if let Some(body) = ["AKIA", "ASIA"].iter().find_map(|p| after(p)) {
if body.len() == 16
&& body
.bytes()
.all(|b| b.is_ascii_uppercase() || b.is_ascii_digit())
{
return Some(TokenKind::AwsAccessKey);
}
}
if let Some(body) = ["xoxa-", "xoxb-", "xoxp-", "xoxr-", "xoxs-"]
.iter()
.find_map(|p| after(p))
{
if body.len() >= 10 && body.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-') {
return Some(TokenKind::Slack);
}
}
if let Some(body) = ["sk_live_", "rk_live_"].iter().find_map(|p| after(p)) {
if body.len() >= 24 && alnum(body) {
return Some(TokenKind::Stripe);
}
}
if let Some(body) = after("AIza") {
if body.len() == 35
&& body
.bytes()
.all(|b| b.is_ascii_alphanumeric() || b == b'_' || b == b'-')
{
return Some(TokenKind::GoogleApiKey);
}
}
if let Some(body) = after("npm_") {
if body.len() == 36 && alnum(body) {
return Some(TokenKind::Npm);
}
}
if is_jwt(token) {
return Some(TokenKind::Jwt);
}
None
}
pub(crate) fn is_private_key_header(text: &str) -> bool {
text.strip_prefix("-----BEGIN ")
.and_then(|rest| rest.strip_suffix("-----"))
.is_some_and(|label| label.ends_with("PRIVATE KEY"))
}
fn is_jwt(token: &str) -> bool {
let parts: Vec<&str> = token.split('.').collect();
parts.len() == 3
&& parts[0].starts_with("eyJ")
&& parts.iter().all(|part| {
!part.is_empty()
&& part
.bytes()
.all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_')
})
}
#[cfg(test)]
#[path = "detect.test.rs"]
mod tests;
#[cfg(test)]
#[path = "detect.spec.rs"]
mod spec;