authentication overhaul
This commit is contained in:
parent
22c1abd093
commit
ba11df89c8
@ -2,5 +2,6 @@
|
|||||||
"api_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
"api_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||||
"base_api": "/api/v1",
|
"base_api": "/api/v1",
|
||||||
"base_url": "https://www.example.com",
|
"base_url": "https://www.example.com",
|
||||||
"username": "jimmyjoebob"
|
"username": "jimmyjoebob",
|
||||||
|
"password": "ihazcheeseburgerz"
|
||||||
}
|
}
|
@ -18,7 +18,7 @@ pub fn get_args() -> ArgMatches<'static> {
|
|||||||
.arg(Arg::with_name("search")
|
.arg(Arg::with_name("search")
|
||||||
.short("s")
|
.short("s")
|
||||||
.long("search")
|
.long("search")
|
||||||
.value_name("REPO")
|
.value_names(&["REPO"])
|
||||||
.help("Search repositories for a user")
|
.help("Search repositories for a user")
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("list")
|
.arg(Arg::with_name("list")
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use config::File;
|
use config::File;
|
||||||
use serde::{Deserialize};
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
pub api_token: String,
|
pub api_token: Option<String>,
|
||||||
pub base_api: String,
|
pub base_api: String,
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
pub username: Option<String>
|
pub username: Option<String>,
|
||||||
|
pub password: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Configuration {
|
impl Configuration {
|
||||||
|
15
src/main.rs
15
src/main.rs
@ -7,21 +7,25 @@ mod arg;
|
|||||||
mod config;
|
mod config;
|
||||||
mod issue;
|
mod issue;
|
||||||
mod repo;
|
mod repo;
|
||||||
|
mod request;
|
||||||
|
|
||||||
use clap::{ArgMatches};
|
use clap::ArgMatches;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let matches: ArgMatches = arg::get_args();
|
let mut matches: ArgMatches = arg::get_args();
|
||||||
let config = crate::config::Configuration::new();
|
let mut config = crate::config::Configuration::new();
|
||||||
|
|
||||||
match matches.subcommand() {
|
let auth = request::Authentication::new(&config);
|
||||||
|
let request = auth.request_chooser(config.clone(), matches);
|
||||||
|
|
||||||
|
match request.arg_value.subcommand() {
|
||||||
("", None) => println!("No subcommand was given!"),
|
("", None) => println!("No subcommand was given!"),
|
||||||
("repo", Some(repo_matches)) => {
|
("repo", Some(repo_matches)) => {
|
||||||
let repo = repo::Repository::new();
|
let repo = repo::Repository::new();
|
||||||
|
|
||||||
// TODO: match expression should be here
|
// TODO: match expression should be here
|
||||||
if repo_matches.is_present("create") {
|
if repo_matches.is_present("create") {
|
||||||
repo.create_repo(&config, repo_matches);
|
repo.create_repo(&request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo_matches.is_present("delete") {
|
if repo_matches.is_present("delete") {
|
||||||
@ -51,3 +55,4 @@ fn main() {
|
|||||||
_ => println!("Huh?")
|
_ => println!("Huh?")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
src/repo.rs
26
src/repo.rs
@ -6,6 +6,7 @@ use reqwest::{StatusCode, Client};
|
|||||||
use serde_derive::{Serialize, Deserialize};
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::config::Configuration;
|
use crate::config::Configuration;
|
||||||
|
use crate::request::Request;
|
||||||
|
|
||||||
pub struct Repository;
|
pub struct Repository;
|
||||||
|
|
||||||
@ -102,14 +103,17 @@ impl Repository {
|
|||||||
Repository {}
|
Repository {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_repo(&self, config: &Configuration, arg: &ArgMatches) {
|
pub fn create_repo(&self, request: &Request) {
|
||||||
let client = Client::new();
|
let client = &request.client;
|
||||||
let arg_value = arg.value_of("create").unwrap();
|
let arg_value = request.arg_value.subcommand().1.unwrap().value_of("create").unwrap();
|
||||||
let mut map: HashMap<&str, &str> = HashMap::new();
|
let mut map: HashMap<&str, &str> = HashMap::new();
|
||||||
let url = format!("{base_url}{base_api}/user/repos?token={api_token}",
|
let url = format!("{request}/user/repos?token={api_token}",
|
||||||
base_url = config.base_url,
|
request = request.url.as_ref().unwrap(),
|
||||||
base_api = config.base_api,
|
api_token = request
|
||||||
api_token = config.api_token);
|
.authentication
|
||||||
|
.credentials
|
||||||
|
.1.as_ref()
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
map.insert("name", arg_value);
|
map.insert("name", arg_value);
|
||||||
map.insert("readme", arg_value);
|
map.insert("readme", arg_value);
|
||||||
@ -147,7 +151,7 @@ impl Repository {
|
|||||||
base_api = config.base_api,
|
base_api = config.base_api,
|
||||||
username = arg_iter[0],
|
username = arg_iter[0],
|
||||||
repo_name = arg_iter[1],
|
repo_name = arg_iter[1],
|
||||||
api_token = config.api_token);
|
api_token = config.api_token.as_ref().unwrap());
|
||||||
|
|
||||||
let response = client.delete(&url)
|
let response = client.delete(&url)
|
||||||
.send();
|
.send();
|
||||||
@ -182,7 +186,7 @@ impl Repository {
|
|||||||
base_api = config.base_api,
|
base_api = config.base_api,
|
||||||
owner = arg_item[0],
|
owner = arg_item[0],
|
||||||
repo = arg_item[1],
|
repo = arg_item[1],
|
||||||
api_token = config.api_token);
|
api_token = config.api_token.as_ref().unwrap());
|
||||||
|
|
||||||
map.insert("name", user.as_str());
|
map.insert("name", user.as_str());
|
||||||
|
|
||||||
@ -216,7 +220,7 @@ impl Repository {
|
|||||||
base_url = config.base_url,
|
base_url = config.base_url,
|
||||||
base_api = config.base_api,
|
base_api = config.base_api,
|
||||||
query = arg_value,
|
query = arg_value,
|
||||||
api_token = config.api_token);
|
api_token = config.api_token.as_ref().unwrap());
|
||||||
|
|
||||||
let response = client.get(url.as_str())
|
let response = client.get(url.as_str())
|
||||||
.send();
|
.send();
|
||||||
@ -255,7 +259,7 @@ impl Repository {
|
|||||||
let url = format!("{base_url}{base_api}/repos/search?token={api_token}",
|
let url = format!("{base_url}{base_api}/repos/search?token={api_token}",
|
||||||
base_url = config.base_url,
|
base_url = config.base_url,
|
||||||
base_api = config.base_api,
|
base_api = config.base_api,
|
||||||
api_token = config.api_token);
|
api_token = config.api_token.as_ref().unwrap());
|
||||||
|
|
||||||
let response = client.get(url.as_str())
|
let response = client.get(url.as_str())
|
||||||
.send();
|
.send();
|
||||||
|
@ -7,28 +7,55 @@ use crate::config::Configuration;
|
|||||||
|
|
||||||
pub struct Request<'a> {
|
pub struct Request<'a> {
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub arg_value: Vec<&'a str>,
|
pub arg_value: ArgMatches<'a>,
|
||||||
pub map: HashMap<String, String>,
|
pub map: HashMap<String, String>,
|
||||||
pub url: Option<String>,
|
pub url: Option<String>,
|
||||||
|
pub authentication: Authentication,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Authentication {
|
pub struct Authentication {
|
||||||
pub basic: bool,
|
pub basic: bool,
|
||||||
pub api_token: bool,
|
pub api_token: bool,
|
||||||
|
pub credentials: (Option<String>, Option<String>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request<'static> {
|
impl<'a> Request<'a> {
|
||||||
fn new() -> Request<'static> {
|
/// Public constructor for a request with a simple username and password
|
||||||
|
pub fn with_basic_request(
|
||||||
|
config: Configuration,
|
||||||
|
arg: ArgMatches,
|
||||||
|
auth: Authentication
|
||||||
|
) -> Request {
|
||||||
Request {
|
Request {
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
arg_value: Vec::new(),
|
arg_value: arg,
|
||||||
map: HashMap::new(),
|
map: HashMap::new(),
|
||||||
url: None
|
url: Some(format!("{:?}{:?}", config.base_url, config.base_api)),
|
||||||
|
authentication: auth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Public constructor for a request with an API token
|
||||||
|
pub fn with_api_request(
|
||||||
|
config: Configuration,
|
||||||
|
arg: ArgMatches,
|
||||||
|
auth: Authentication
|
||||||
|
) -> Request {
|
||||||
|
Request {
|
||||||
|
client: Client::new(),
|
||||||
|
arg_value: arg,
|
||||||
|
map: HashMap::new(),
|
||||||
|
url: Some(format!("{:?}{:?}", config.base_url, config.base_api)),
|
||||||
|
authentication: auth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Authentication {
|
impl Authentication{
|
||||||
|
/// Public constructor for getting authentication, provided by the configuration
|
||||||
|
/// file. The most secure methods are checked first, filtering down to the least
|
||||||
|
/// secure methods. Currently, only two methods are supported: API token, and
|
||||||
|
/// username/password combo.
|
||||||
pub fn new(config: &Configuration) -> Authentication {
|
pub fn new(config: &Configuration) -> Authentication {
|
||||||
let basic_auth: String;
|
let basic_auth: String;
|
||||||
let api_auth: String;
|
let api_auth: String;
|
||||||
@ -37,28 +64,67 @@ impl Authentication {
|
|||||||
// this is horror code, I know it
|
// this is horror code, I know it
|
||||||
// match the damn thing
|
// match the damn thing
|
||||||
// someone is going to take this and put it in r/badcode lol
|
// someone is going to take this and put it in r/badcode lol
|
||||||
|
basic_auth = config
|
||||||
|
.password
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
match config {
|
api_auth = config
|
||||||
_ => panic!()
|
.api_token
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
if api_auth.is_empty() {
|
||||||
|
if !(basic_auth.is_empty()) {
|
||||||
|
Authentication::with_basic(config.username.as_ref().unwrap().to_string(), basic_auth)
|
||||||
|
} else {
|
||||||
|
panic!("Must have some form of authentication! Exiting...");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Authentication::with_api_token(api_auth)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_basic() -> Authentication {
|
/// Private constructor once the public constructor figures out what kind of authentication
|
||||||
|
/// is being used. This constructor uses the username/password combo, a less secure of
|
||||||
|
/// authenticating that the API token.
|
||||||
|
fn with_basic(user: String, pass: String) -> Authentication {
|
||||||
Authentication {
|
Authentication {
|
||||||
basic: true,
|
basic: true,
|
||||||
api_token: false
|
api_token: false,
|
||||||
|
credentials: (Some(user), Some(pass))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_api_token() -> Authentication {
|
/// Private constructor once the public constructor figures out what kind of authentication
|
||||||
|
/// is being used. This constructor uses the API token, a more secure way of authenticating
|
||||||
|
/// instead of using the basic username and password.
|
||||||
|
fn with_api_token(api_token: String) -> Authentication {
|
||||||
Authentication {
|
Authentication {
|
||||||
basic: false,
|
basic: false,
|
||||||
api_token: true
|
api_token: true,
|
||||||
|
credentials: (Some(api_token), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method requires the instanciated config, an optional instanciated args, and instanciated auth
|
/// Public method that based on the what kind of authentication is being used, it can
|
||||||
pub fn request_chooser(&self, config: &Configuration, arg: Option<&ArgMatches>, auth: &Authentication, arg_string: &str) {
|
/// determine what kind of requesting method is going to be used. See the Request
|
||||||
|
/// structure for more details.
|
||||||
|
pub fn request_chooser(
|
||||||
|
self,
|
||||||
|
config: Configuration,
|
||||||
|
arg: ArgMatches<'static>,
|
||||||
|
) -> Request {
|
||||||
|
if let true = self.api_token {
|
||||||
|
Request::with_api_request(config, arg.to_owned(), self)
|
||||||
|
} else {
|
||||||
|
match self.basic {
|
||||||
|
true => Request::with_basic_request(config, arg.to_owned(), self),
|
||||||
|
false => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user