forked from mirrors/kingfisher
working
This commit is contained in:
parent
9cf22e27fc
commit
6048462041
4 changed files with 140 additions and 20 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -5273,6 +5273,7 @@ name = "kingfisher-rules"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base32",
|
||||
"base64 0.22.1",
|
||||
"crc32fast",
|
||||
"hmac 0.12.1",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ liquid = "0.26"
|
|||
liquid-core = "0.26"
|
||||
|
||||
# Crypto for liquid filters
|
||||
base32 = "0.5"
|
||||
base64.workspace = true
|
||||
crc32fast = "1.5"
|
||||
hmac.workspace = true
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ rules:
|
|||
pattern: |
|
||||
(?x)
|
||||
(
|
||||
github_pat_
|
||||
(?P<body>[0-9][A-Za-z0-9]{21}_[A-Za-z0-9]{43})
|
||||
(?P<checksum>[A-Za-z0-9]{8})
|
||||
(?P<body>github_pat_[0-9][A-Za-z0-9]{21}_[A-Za-z0-9]{43})
|
||||
(?P<checksum>[A-Za-z2-7]{8})
|
||||
[A-Za-z0-9]{8}
|
||||
)
|
||||
\b
|
||||
|
|
@ -17,7 +16,7 @@ rules:
|
|||
actual:
|
||||
template: "{{ checksum }}"
|
||||
requires_capture: checksum
|
||||
expected: "{{ body | crc32 | base62: 8 }}"
|
||||
expected: "{{ body | sha256_b32: 8 }}"
|
||||
skip_if_missing: true
|
||||
min_entropy: 3.5
|
||||
examples:
|
||||
|
|
@ -58,9 +57,9 @@ rules:
|
|||
- name: GitHub Personal Access Token
|
||||
id: kingfisher.github.2
|
||||
pattern: |
|
||||
(?xi)
|
||||
(?x)
|
||||
(
|
||||
ghp_(?P<body>[A-Z0-9]{30})(?P<checksum>[A-Z0-9]{6})
|
||||
ghp_(?P<body>[A-Za-z0-9]{30})(?P<checksum>[A-Za-z0-9]{6})
|
||||
)
|
||||
pattern_requirements:
|
||||
min_digits: 2
|
||||
|
|
@ -114,9 +113,9 @@ rules:
|
|||
- name: GitHub OAuth Access Token
|
||||
id: kingfisher.github.3
|
||||
pattern: |
|
||||
(?xi)
|
||||
(?x)
|
||||
(
|
||||
gho_(?P<body>[A-Z0-9]{30})(?P<checksum>[A-Z0-9]{6})
|
||||
gho_(?P<body>[A-Za-z0-9]{30})(?P<checksum>[A-Za-z0-9]{6})
|
||||
)
|
||||
pattern_requirements:
|
||||
min_digits: 2
|
||||
|
|
@ -149,18 +148,40 @@ rules:
|
|||
words:
|
||||
- '"login"'
|
||||
- '"id"'
|
||||
revocation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: POST
|
||||
url: https://api.github.com/credentials/revoke
|
||||
headers:
|
||||
Accept: application/vnd.github+json
|
||||
X-GitHub-Api-Version: 2022-11-28
|
||||
Content-Type: application/json
|
||||
body: '{"credentials":["{{ TOKEN }}"]}'
|
||||
response_matcher:
|
||||
- report_response: true
|
||||
- type: StatusMatch
|
||||
status: [202]
|
||||
- name: GitHub App User-to-Server Token
|
||||
id: kingfisher.github.4
|
||||
pattern: |
|
||||
(?xi)
|
||||
(?x)
|
||||
(
|
||||
ghu_(?P<body>[A-Z0-9]{30})(?P<checksum>[A-Z0-9]{6})
|
||||
ghu_(?P<body>[A-Za-z0-9]{30})(?P<checksum>[A-Za-z0-9]{6})
|
||||
)
|
||||
pattern_requirements:
|
||||
checksum:
|
||||
actual:
|
||||
template: "{{ checksum }}"
|
||||
requires_capture: checksum
|
||||
expected: "{{ body | crc32 | base62: 6 }}"
|
||||
skip_if_missing: true
|
||||
examples:
|
||||
- ' "token": "ghu_16C7e42F292c69C2E7C10c838347Ae178B4a",'
|
||||
- ' "token": "ghu_TIOHHEVefAwRonSMALCFfWMYK0un1R1dj2rn",'
|
||||
- |
|
||||
Example usage:
|
||||
git clone http://ghu_RguXIkihJjwHAP6eXEYxaPNvywurTr5IOAbg@github.com/username/repo.git
|
||||
git clone http://ghu_imqBAXUtRirzzcJPwAiqImhkzsvzYZ1eDtPf@github.com/username/repo.git
|
||||
references:
|
||||
- https://docs.github.com/en/rest/users?apiVersion=2022-11-28
|
||||
validation:
|
||||
|
|
@ -179,15 +200,27 @@ rules:
|
|||
words:
|
||||
- '"login"'
|
||||
- '"id"'
|
||||
# Revocation not supported: ghu_ tokens require the GitHub App's client_id
|
||||
# and client_secret (DELETE /applications/{client_id}/token with Basic auth).
|
||||
# Users can revoke via GitHub Settings > Applications > Authorized GitHub Apps.
|
||||
revocation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: POST
|
||||
url: https://api.github.com/credentials/revoke
|
||||
headers:
|
||||
Accept: application/vnd.github+json
|
||||
X-GitHub-Api-Version: 2022-11-28
|
||||
Content-Type: application/json
|
||||
body: '{"credentials":["{{ TOKEN }}"]}'
|
||||
response_matcher:
|
||||
- report_response: true
|
||||
- type: StatusMatch
|
||||
status: [202]
|
||||
- name: GitHub App Server-to-Server Token
|
||||
id: kingfisher.github.5
|
||||
pattern: |
|
||||
(?xi)
|
||||
(?x)
|
||||
(
|
||||
ghs_(?P<body>[A-Z0-9]{30})(?P<checksum>[A-Z0-9]{6})
|
||||
ghs_(?P<body>[A-Za-z0-9]{30})(?P<checksum>[A-Za-z0-9]{6})
|
||||
)
|
||||
examples:
|
||||
- ' "token": "ghs_16C7e42F292c69C2E7C10c838347Ae178B4a",'
|
||||
|
|
@ -228,12 +261,19 @@ rules:
|
|||
- name: GitHub Refresh Token
|
||||
id: kingfisher.github.6
|
||||
pattern: |
|
||||
(?xi)
|
||||
(?x)
|
||||
(
|
||||
ghr_(?P<body>[A-Z0-9]{30})(?P<checksum>[A-Z0-9]{6})
|
||||
ghr_(?P<body>[A-Za-z0-9]{70})(?P<checksum>[A-Za-z0-9]{6})
|
||||
)
|
||||
pattern_requirements:
|
||||
checksum:
|
||||
actual:
|
||||
template: "{{ checksum }}"
|
||||
requires_capture: checksum
|
||||
expected: "{{ body | crc32 | base62: 6 }}"
|
||||
skip_if_missing: true
|
||||
examples:
|
||||
- ' "refresh_token": "ghr_1B4a2e77838347a7E420ce178F2E7c6912E169246c3CE1ccbF66C46812d16D5B1A9Dc86A1498",'
|
||||
- ' "refresh_token": "ghr_xgrrGzSbbGRL34Wp39JU9nxtN27Pr1v1He8FjE7x7wbExGGs7nfJszJDAmZuoKasxZ0KxJ1HSzgc",'
|
||||
references:
|
||||
- https://docs.github.com/en/rest/users?apiVersion=2022-11-28
|
||||
validation:
|
||||
|
|
@ -252,6 +292,21 @@ rules:
|
|||
words:
|
||||
- '"login"'
|
||||
- '"id"'
|
||||
revocation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: POST
|
||||
url: https://api.github.com/credentials/revoke
|
||||
headers:
|
||||
Accept: application/vnd.github+json
|
||||
X-GitHub-Api-Version: 2022-11-28
|
||||
Content-Type: application/json
|
||||
body: '{"credentials":["{{ TOKEN }}"]}'
|
||||
response_matcher:
|
||||
- report_response: true
|
||||
- type: StatusMatch
|
||||
status: [202]
|
||||
|
||||
- name: GitHub Client ID
|
||||
id: kingfisher.github.7
|
||||
|
|
|
|||
|
|
@ -540,6 +540,56 @@ static_filter!(
|
|||
}
|
||||
);
|
||||
|
||||
// {{ value | sha256_b32 }} -- base32-encoded SHA-256 digest, optional length
|
||||
#[derive(Debug, FilterParameters)]
|
||||
struct Sha256B32Args {
|
||||
#[parameter(description = "Exact output length: truncates if longer, pads with '=' if shorter", arg_type = "integer")]
|
||||
len: Option<Expression>,
|
||||
}
|
||||
|
||||
#[derive(Clone, ParseFilter, FilterReflection, Default)]
|
||||
#[filter(
|
||||
name = "sha256_b32",
|
||||
description = "SHA-256 digest encoded as Base32 (RFC 4648), optionally truncating or padding with '=' to an exact length.",
|
||||
parameters(Sha256B32Args),
|
||||
parsed(Sha256B32)
|
||||
)]
|
||||
pub struct Sha256B32Filter;
|
||||
|
||||
#[derive(Debug, FromFilterParameters, Display_filter)]
|
||||
#[name = "sha256_b32"]
|
||||
struct Sha256B32 {
|
||||
#[parameters]
|
||||
args: Sha256B32Args,
|
||||
}
|
||||
|
||||
impl Filter for Sha256B32 {
|
||||
fn evaluate(&self, input: &dyn ValueView, runtime: &dyn Runtime) -> Result<Value> {
|
||||
let args = self.args.evaluate(runtime)?;
|
||||
let mut h = Sha256::new();
|
||||
h.update(input.to_kstr().as_bytes());
|
||||
let mut encoded = base32::encode(
|
||||
base32::Alphabet::Rfc4648 { padding: true },
|
||||
&h.finalize()[..],
|
||||
);
|
||||
if let Some(len) = args.len.and_then(|value| {
|
||||
let scalar = Value::scalar(value);
|
||||
value_to_usize(&scalar)
|
||||
}) {
|
||||
match encoded.len().cmp(&len) {
|
||||
std::cmp::Ordering::Greater => encoded.truncate(len),
|
||||
std::cmp::Ordering::Less => {
|
||||
for _ in 0..(len - encoded.len()) {
|
||||
encoded.push('=');
|
||||
}
|
||||
}
|
||||
std::cmp::Ordering::Equal => {}
|
||||
}
|
||||
}
|
||||
Ok(Value::scalar(encoded))
|
||||
}
|
||||
}
|
||||
|
||||
static_filter!(
|
||||
/// Compute the CRC32 of the input and return it as a decimal number.
|
||||
Crc32Filter,
|
||||
|
|
@ -1013,6 +1063,7 @@ pub fn register_all(builder: liquid::ParserBuilder) -> liquid::ParserBuilder {
|
|||
.filter(Replace::default())
|
||||
.filter(B64UrlEncFilter::default())
|
||||
.filter(Sha256Filter::default())
|
||||
.filter(Sha256B32Filter::default())
|
||||
.filter(UrlEncodeFilter::default())
|
||||
.filter(JsonEscapeFilter::default())
|
||||
.filter(UnixTimestampFilter::default())
|
||||
|
|
@ -1083,6 +1134,18 @@ mod tests {
|
|||
assert_eq!(render(r#"{{ "hello" | sha256 }}"#), expect);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sha256_b32_filter() {
|
||||
let expect = "FTZE3OS7WCRQ4JXIHMVMLOPCTYNRMHS4D6TUEXTTAQZWFE4LTASA====";
|
||||
assert_eq!(render(r#"{{ "hello" | sha256_b32 }}"#), expect);
|
||||
// truncate
|
||||
assert_eq!(render(r#"{{ "hello" | sha256_b32: 4 }}"#), &expect[..4]);
|
||||
// pad
|
||||
let padded = render(r#"{{ "hello" | sha256_b32: 60 }}"#);
|
||||
assert!(padded.ends_with("===="));
|
||||
assert_eq!(padded.len(), 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suffix_filter() {
|
||||
assert_eq!(render(r#"{{ "abcdef" | suffix: 3 }}"#), "def");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue