summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs723
1 files changed, 42 insertions, 681 deletions
diff --git a/src/main.rs b/src/main.rs
index d06fa9a..dd0041c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,6 @@
+mod parser;
+use crate::parser::*;
+
use base64::prelude::*;
use yaml_rust2::parser::Parser;
use yaml_rust2::Event;
@@ -16,6 +19,45 @@ Options:
);
}
+#[derive(Debug)]
+enum AuthMethod {
+ Basic,
+ Bearer{realm: String, service: String, scope: String},
+}
+
+impl AuthMethod {
+ fn from_header(header: &ureq::http::HeaderValue) -> Option<Self> {
+ let header_str = header.to_str().unwrap();
+ let (parse, _) = parse_challenge(&header_str.chars().collect::<Vec<char>>(), 0).unwrap();
+
+ if &header_str[parse.scheme.clone()] == "Basic" {
+ return Some(AuthMethod::Basic);
+ }
+
+ if &header_str[parse.scheme.clone()] == "Bearer" {
+ let mut realm_param = None;
+ let mut scope_param = None;
+ let mut service_param = None;
+ for param in parse.params {
+ match &header_str[param.key.clone()] {
+ "realm" => realm_param = Some(param),
+ "scope" => scope_param = Some(param),
+ "service" => service_param = Some(param),
+ _ => {},
+ }
+ }
+
+ return Some(AuthMethod::Bearer{
+ realm: header_str[realm_param.unwrap().value].to_string(),
+ scope: header_str[scope_param.unwrap().value].to_string(),
+ service: header_str[service_param.unwrap().value].to_string(),
+ });
+ }
+
+ return None;
+ }
+}
+
struct AuthInfo {
host: String,
username: String,
@@ -109,687 +151,6 @@ impl AuthState{
}
}
-#[derive(Debug)]
-enum AuthMethod {
- Basic,
- Bearer{realm: String, service: String, scope: String},
-}
-
-#[derive(Debug)]
-struct Challenge {
- scheme: Range<usize>,
- params: Vec<AuthParam>,
-}
-
-fn parse_token(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
- while str.len() > pos {
- match str[pos] {
- 'a'..'z' | 'A'..'Z' => pos += 1,
- _ => break,
- }
- }
-
- if pos == start {
- return None;
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_qdtext(str: &Vec<char>, start: usize) -> Option<usize> {
- match str[start] {
- '\x00'..'\x1F' | '"' | '\x7F' => return None,
- _ => return Some(start + 1),
- }
-}
-
-fn parse_quotedpair(str: &Vec<char>, start: usize) -> Option<usize> {
- if str[start] != '\\' {
- return None;
- }
-
- return Some(start + 2);
-}
-
-fn parse_quotedstring(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
- if str[pos] != '"' {
- return None;
- }
- pos += 1;
-
- loop {
- if let Some(npos) = parse_qdtext(str, pos) {
- pos = npos;
- } else if let Some(npos) = parse_quotedpair(str, pos) {
- pos = npos;
- } else {
- break;
- }
- }
-
- if str[pos] != '"' {
- return None;
- }
- pos += 1;
-
- return Some((start+1..pos-1, pos));
-}
-
-fn parse_sp(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- if str.len() <= start {
- return None;
- }
-
- let mut pos = start;
- match str[pos] {
- ' ' => pos += 1,
- _ => return None,
- }
-
- if pos == start {
- return None;
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_crlf(str: &Vec<char>, start: usize) -> Option<usize> {
- if str.len() - 2 < start {
- return None;
- }
-
- if str[start] == '\r' && str[start+1] == '\n' {
- return Some(start + 2);
- }
-
- return None;
-}
-
-fn parse_lws(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- match parse_crlf(str, pos) {
- Some(npos) => pos = npos,
- None => {},
- }
-
- match parse_sp(str, pos) {
- Some((_, npos)) => pos = npos,
- None => return None,
- }
- loop {
- match parse_sp(str, pos) {
- Some((_, npos)) => pos = npos,
- None => break,
- }
- }
-
- return Some((start..pos, pos));
-}
-
-#[derive(Debug)]
-struct AuthParam {
- key: Range<usize>,
- value: Range<usize>,
-}
-
-fn parse_param(str: &Vec<char>, start: usize) -> Option<(AuthParam, usize)> {
- let pos = start;
- let (param_range, pos) = parse_token(str, pos)?;
-
- let mut pos = pos;
- if str[pos] == '=' {
- pos += 1;
- } else {
- todo!();
- }
-
- let value_range;
- if let Some((range, npos)) = parse_token(str, pos) {
- value_range = range;
- pos = npos;
- } else if let Some((range, npos)) = parse_quotedstring(str, pos) {
- value_range = range;
- pos = npos;
- } else {
- todo!("{:?}", &str[pos..]);
- }
-
- return Some((AuthParam{key: param_range, value: value_range}, pos));
-}
-
-fn parse_challenge(str: &Vec<char>, start: usize) -> Option<(Challenge, usize)> {
- let pos = start;
- let (scheme_range, pos) = parse_token(str, pos).unwrap();
-
- let (_, pos) = parse_sp(str, pos).unwrap();
- let mut pos = pos;
- loop {
- match parse_sp(str, pos) {
- Some((_, npos)) => pos = npos,
- None => break,
- }
- }
-
- let mut params = vec!();
-
- let mut pos = pos;
- loop {
- match parse_lws(str, pos) {
- Some((_, npos)) => pos = npos,
- None => break,
- }
- }
- let (param, pos) = parse_param(str, pos).unwrap();
- params.push(param);
- let mut pos = pos;
- loop {
- loop {
- match parse_lws(str, pos) {
- Some((_, npos)) => pos = npos,
- None => break,
- }
- }
-
- if pos >= str.len() || str[pos] != ',' {
- break;
- }
- pos += 1;
-
- loop {
- match parse_lws(str, pos) {
- Some((_, npos)) => pos = npos,
- None => break,
- }
- }
-
- match parse_param(str, pos) {
- Some((param, npos)) => {
- pos = npos;
- params.push(param);
- },
- None => return None,
- }
- }
-
- if pos < str.len() {
- return None;
- }
- return Some((Challenge {scheme: scheme_range, params}, pos));
-}
-
-impl AuthMethod {
- fn from_header(header: &ureq::http::HeaderValue) -> Option<Self> {
- let header_str = header.to_str().unwrap();
- let (parse, _) = parse_challenge(&header_str.chars().collect::<Vec<char>>(), 0).unwrap();
-
- if &header_str[parse.scheme.clone()] == "Basic" {
- return Some(AuthMethod::Basic);
- }
-
- if &header_str[parse.scheme.clone()] == "Bearer" {
- let mut realm_param = None;
- let mut scope_param = None;
- let mut service_param = None;
- for param in parse.params {
- match &header_str[param.key.clone()] {
- "realm" => realm_param = Some(param),
- "scope" => scope_param = Some(param),
- "service" => service_param = Some(param),
- _ => {},
- }
- }
-
- return Some(AuthMethod::Bearer{
- realm: header_str[realm_param.unwrap().value].to_string(),
- scope: header_str[scope_param.unwrap().value].to_string(),
- service: header_str[service_param.unwrap().value].to_string(),
- });
- }
-
- return None;
- }
-}
-
-#[derive(Debug)]
-enum LinkParam {
- Rel{relation: Range<usize>},
-}
-
-impl LinkParam {
- fn value(&self) -> &Range<usize> {
- match self {
- LinkParam::Rel{relation} => &relation,
- }
- }
-}
-
-#[derive(Debug)]
-struct LinkValue {
- uri: Range<usize>,
- params: Vec<LinkParam>,
-}
-
-fn parse_alpha(str: &Vec<char>, pos: usize) -> Option<(Range<usize>, usize)> {
- return match str[pos] {
- 'a'..'z' | 'A'..'Z' => Some((pos..pos+1, pos+1)),
- _ => None,
- }
-}
-
-fn parse_digit(str: &Vec<char>, pos: usize) -> Option<(Range<usize>, usize)> {
- return match str[pos] {
- '0'..'9' => Some((pos..pos+1, pos+1)),
- _ => None,
- }
-}
-
-fn parse_scheme(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- let (_, npos) = parse_alpha(str, pos)?;
- pos = npos;
-
- loop {
- if let Some((_, npos)) = parse_alpha(str, pos) {
- pos = npos;
- } else {
- break;
- }
- };
-
- return None;
-}
-
-fn parse_authority(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- return None;
-}
-
-fn parse_relative_part_1(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- if str[pos] != '/' && str[pos+1] != '/' {
- return None;
- }
- pos += 2;
-
- let (_, npos) = parse_authority(str, pos)?;
- pos = npos;
-
- return Some((start..pos, pos));
-}
-
-fn parse_unreserved(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- if let Some(x) = parse_alpha(str, start) {
- return Some(x);
- }
-
- if let Some(x) = parse_digit(str, start) {
- return Some(x);
- }
-
- match str[start] {
- '-' | '.' | '_' | '~' => Some((start..start+1, start+1)),
- _ => None
- }
-}
-
-fn parse_sub_delims(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- match str[start] {
- '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | ';' | '=' => Some((start..start+1, start+1)),
- _ => None
- }
-
-}
-
-fn parse_pchar(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- if let Some(x) = parse_unreserved(str, start) {
- return Some(x);
- }
-
- if let Some(x) = parse_sub_delims(str, start) {
- return Some(x);
- }
-
- return None;
-}
-
-fn parse_segment_nz(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- let (_, npos) = parse_pchar(str, pos)?;
- pos = npos;
-
- loop {
- if let Some((_, npos)) = parse_pchar(str, pos) {
- pos = npos;
- } else {
- break;
- }
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_segment(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- loop {
- if let Some((_, npos)) = parse_pchar(str, pos) {
- pos = npos;
- } else {
- break;
- }
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_path_absolute(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- if str[pos] != '/' {
- return None;
- }
- pos += 1;
-
- if let Some((_, npos)) = parse_segment_nz(str, pos) {
- pos = npos;
-
- loop {
- if str[pos] != '/' {
- break;
- }
-
- if let Some((_, npos)) = parse_segment(str, pos+1) {
- pos = npos;
- } else {
- break;
- }
- }
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_relative_part(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- if let Some((_, npos)) = parse_relative_part_1(str, pos) {
- pos = npos;
- return Some((start..pos, pos));
- }
-
- if let Some((_, npos)) = parse_path_absolute(str, pos) {
- pos = npos;
- return Some((start..pos, pos));
- }
-
- return None;
-}
-
-fn parse_query(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- loop {
- if let Some((_, npos)) = parse_pchar(str, pos) {
- pos = npos;
- } else if str[pos] == '/' {
- pos += 1;
- } else if str[pos] == '?' {
- pos += 1;
- } else {
- break;
- }
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_fragment(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- return None;
-}
-
-fn parse_relative_ref(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- let (_, npos) = parse_relative_part(str, pos)?;
- pos = npos;
-
- if str[pos] == '?' && let Some((_, npos)) = parse_query(str, pos+1) {
- pos = npos;
- }
-
- if str[pos] == '#' && let Some((_, npos)) = parse_fragment(str, pos+1) {
- pos = npos;
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_uri(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- let(_, npos) = parse_scheme(str, pos)?;
- pos = npos;
-
- return Some((start..pos, pos));
-}
-
-fn parse_exact_string(str: &Vec<char>, start: usize, to_match: &str) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
- let end = pos + to_match.len();
-
- if end > str.len() {
- return None;
- }
-
- if !to_match.chars().eq(str[start..start+to_match.len()].iter().map(|x| *x)) {
- return None;
- }
- pos += to_match.len();
-
- return Some((start..pos, pos));
-}
-
-fn parse_loalpha(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- match str[start] {
- 'a'..'z' => Some((start..start+1, start+1)),
- _ => None,
- }
-}
-
-fn parse_relation_type(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- let (_, npos) = parse_loalpha(str, pos)?;
- pos = npos;
-
- loop {
- dbg!(&str[pos..]);
- if let Some((_, npos)) = parse_loalpha(str, pos) {
- pos = npos;
- continue;
- } else if let Some((_, npos)) = parse_digit(str, pos) {
- pos = npos;
- continue;
- } else if let Some((_, npos)) = parse_exact_string(str, pos, ".") {
- pos = npos;
- continue;
- } else if let Some((_, npos)) = parse_exact_string(str, pos, "-") {
- pos = npos;
- continue;
- } else {
- break;
- }
- }
-
- return Some((start..pos, pos));
-}
-
-fn parse_relation_types(str: &Vec<char>, start: usize) -> Option<(Range<usize>, usize)> {
- let mut pos = start;
-
- if let Some((_, npos)) = parse_relation_type(str, pos) {
- pos = npos;
-
- return Some((start..pos, pos));
- } else if let Some((_, npos)) = parse_exact_string(str, pos, "\"") {
- pos = npos;
-
- if let Some((_, npos)) = parse_relation_type(str, pos) {
- pos = npos;
-
- loop {
- if let Some((_, npos)) = parse_sp(str, pos) {
-
- loop {
- if let Some((_, npos)) = parse_sp(str, pos) {
- pos = npos;
- } else {
- break;
- }
- }
-
- pos = npos;
- if let Some((_, npos)) = parse_relation_type(str, pos) {
- pos = npos;
- continue;
- }
- }
- break;
- }
-
- if let Some((_, npos)) = parse_exact_string(str, pos, "\"") {
- pos = npos;
- return Some((start+1..pos-1, pos));
- }
- }
- }
-
- return None;
-}
-
-fn parse_link_param(str: &Vec<char>, start: usize) -> Option<(LinkParam, usize)> {
- let mut pos = start;
-
- // Non-standard but seen in the wild
- if let Some((_, npos)) = parse_sp(str, pos) {
- pos = npos;
- }
-
- if let Some((_, npos)) = parse_exact_string(str, pos, "rel=") {
- if let Some((relation, npos)) = parse_relation_types(str, npos) {
- pos = npos;
- return Some((LinkParam::Rel{relation}, pos));
- }
- }
-
- return None;
-}
-
-fn parse_link_value(str: &Vec<char>, start: usize) -> Option<(LinkValue, usize)> {
- let mut pos = start;
-
- if str[pos] == '<' {
- pos += 1;
- } else {
- return None;
- }
-
- let uri_range;
- let mut params = vec!();
-
- if let Some((range, npos)) = parse_uri(str, pos) {
- uri_range = range;
- pos = npos;
- } else if let Some((range, npos)) = parse_relative_ref(str, pos) {
- uri_range = range;
- pos = npos;
- } else {
- return None;
- }
-
- if str[pos] == '>' {
- pos += 1;
- } else {
- return None;
- }
-
- loop {
- if let Some((_, npos)) = parse_exact_string(str, pos, ";") {
- pos = npos;
- } else {
- break;
- }
-
- if let Some((param, npos)) = parse_link_param(str, pos) {
- pos = npos;
- params.push(param);
- } else {
- break;
- }
- }
-
- return Some((LinkValue{ uri: uri_range, params: params }, pos));
-}
-
-fn parse_link(str: &Vec<char>, start: usize) -> Option<(Vec<LinkValue>, usize)> {
- let mut pos = start;
-
- let mut values = vec!();
-
- loop {
- match parse_lws(str, pos) {
- Some((_, npos)) => pos = npos,
- None => break,
- }
- }
-
- let (param, npos) = parse_link_value(str, pos)?;
- values.push(param);
- pos = npos;
-
- loop {
- let mut ipos = pos;
- loop {
- match parse_lws(str, ipos) {
- Some((_, npos)) => ipos = npos,
- None => break,
- }
- }
-
- if ipos >= str.len() || str[ipos] != ',' {
- break;
- }
- ipos += 1;
-
- loop {
- match parse_lws(str, ipos) {
- Some((_, npos)) => ipos = npos,
- None => break,
- }
- }
-
- match parse_link_value(str, ipos) {
- Some((param, npos)) => {
- ipos = npos;
- values.push(param);
- },
- None => {
- break;
- },
- }
-
- pos = ipos;
- }
-
-
- return Some((values, pos));
-}
-
fn perform_registry_request(registry: &str, url: &str, auth: &mut Auth) -> Result<ureq::http::Response<ureq::Body>, ()> {
let mut state = auth.states.get_mut(registry);