cli.rs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. use crate::{cert, client_management, schema::{self, schema}, server, user_management, config, token};
  2. use clap::{Parser, Subcommand};
  3. use microrm::prelude::*;
  4. #[derive(Debug, Parser)]
  5. #[clap(author, version, about, long_about = None)]
  6. struct RootArgs {
  7. #[clap(short, long, default_value_t = String::from("uauth.db"))]
  8. /// Database path
  9. db: String,
  10. #[clap(short, long, default_value_t = String::from("primary"))]
  11. /// Which realm to use, for non-server only
  12. realm: String,
  13. #[clap(subcommand)]
  14. command: Command,
  15. }
  16. #[derive(Debug, Subcommand)]
  17. enum Command {
  18. Init,
  19. Cert(CertArgs),
  20. Client(ClientArgs),
  21. Config(ConfigArgs),
  22. Group(GroupArgs),
  23. Server(ServerArgs),
  24. Token(TokenArgs),
  25. User(UserArgs),
  26. }
  27. impl RootArgs {
  28. async fn run(&self) {
  29. if let Command::Init = self.command {
  30. return self.init().await;
  31. }
  32. let storage = microrm::DB::new(schema::schema(), &self.db, microrm::CreateMode::MustExist);
  33. if let Err(e) = storage {
  34. println!("Error occured while loading database: {}", e);
  35. return;
  36. }
  37. let storage = storage.unwrap();
  38. match &self.command {
  39. Command::Init => unreachable!(),
  40. Command::Cert(v) => v.run(&self, storage).await,
  41. Command::Config(v) => v.run(&self, storage).await,
  42. Command::Client(v) => v.run(&self, storage).await,
  43. Command::Group(v) => v.run(&self, storage).await,
  44. Command::Server(v) => v.run(&self, storage).await,
  45. Command::Token(v) => v.run(&self, storage).await,
  46. Command::User(v) => v.run(&self, storage).await,
  47. }
  48. }
  49. async fn init(&self) {
  50. // first check to see if the database is already vaguely set up
  51. let maybedb = microrm::DB::new(schema::schema(), &self.db, microrm::CreateMode::MustExist);
  52. if maybedb.is_ok() {
  53. println!("Database already initialized, not overwriting!");
  54. return;
  55. }
  56. println!("Initializing!");
  57. let db = microrm::DB::new(
  58. schema::schema(),
  59. &self.db,
  60. microrm::CreateMode::AllowNewDatabase,
  61. )
  62. .expect("Unable to initialize database!");
  63. // create primary realm
  64. db.query_interface()
  65. .add(&schema::Realm {
  66. shortname: "primary".to_string(),
  67. })
  68. .expect("couldn't add realm");
  69. }
  70. }
  71. #[derive(Debug, Subcommand)]
  72. enum CertCommand {
  73. Inspect,
  74. Generate,
  75. }
  76. #[derive(Debug, Parser)]
  77. struct CertArgs {
  78. #[clap(subcommand)]
  79. command: CertCommand,
  80. }
  81. impl CertArgs {
  82. async fn run(&self, root: &RootArgs, db: microrm::DB) {
  83. match &self.command {
  84. CertCommand::Inspect => {
  85. cert::inspect(&db, &root.realm);
  86. }
  87. CertCommand::Generate => {
  88. cert::generate(&db, &root.realm);
  89. }
  90. }
  91. }
  92. }
  93. #[derive(Debug, Subcommand)]
  94. enum ClientCommand {
  95. Create { name: String },
  96. List,
  97. Inspect { name: String },
  98. }
  99. #[derive(Debug, Parser)]
  100. struct ClientArgs {
  101. #[clap(subcommand)]
  102. command: ClientCommand,
  103. }
  104. impl ClientArgs {
  105. async fn run(&self, root: &RootArgs, db: microrm::DB) {
  106. match &self.command {
  107. ClientCommand::Create { name } => {
  108. client_management::create(&db, root.realm.as_str(), name);
  109. }
  110. ClientCommand::List => {}
  111. ClientCommand::Inspect { name } => {
  112. client_management::inspect(&db, name);
  113. }
  114. }
  115. }
  116. }
  117. #[derive(Debug, Subcommand)]
  118. enum ConfigCommand {
  119. Dump,
  120. Load {
  121. toml_path: String
  122. },
  123. Set {
  124. key: String,
  125. value: String,
  126. }
  127. }
  128. #[derive(Debug, Parser)]
  129. struct ConfigArgs {
  130. #[clap(subcommand)]
  131. command: ConfigCommand,
  132. }
  133. impl ConfigArgs {
  134. async fn run(&self, root: &RootArgs, db: microrm::DB) {
  135. match &self.command {
  136. ConfigCommand::Dump => {
  137. let qi = db.query_interface();
  138. let config = config::Config::build_from(&qi, None);
  139. println!("config: {:?}", config);
  140. },
  141. ConfigCommand::Set { key, value } => {
  142. todo!()
  143. },
  144. ConfigCommand::Load { toml_path } => {
  145. let config = {
  146. let qi = db.query_interface();
  147. config::Config::build_from(&qi, Some(toml_path))
  148. };
  149. {
  150. let qi = db.query_interface();
  151. config.save(&qi);
  152. drop(config);
  153. }
  154. },
  155. }
  156. }
  157. }
  158. #[derive(Debug, Subcommand)]
  159. enum GroupCommand {}
  160. #[derive(Debug, Parser)]
  161. struct GroupArgs {
  162. #[clap(subcommand)]
  163. command: GroupCommand,
  164. }
  165. impl GroupArgs {
  166. async fn run(&self, root: &RootArgs, db: microrm::DB) {}
  167. }
  168. #[derive(Debug, Parser)]
  169. struct ServerArgs {
  170. #[clap(short, long)]
  171. port: Option<u16>,
  172. #[clap(short, long)]
  173. config_path: Option<String>,
  174. }
  175. impl ServerArgs {
  176. async fn run(&self, root: &RootArgs, db: microrm::DB) {
  177. let config = config::Config::build_from(
  178. &db.query_interface(),
  179. self.config_path.as_ref().map(|x| x.as_str()),
  180. );
  181. server::run_server(db, config, self.port.unwrap_or(2114)).await
  182. }
  183. }
  184. #[derive(Debug, Subcommand)]
  185. enum TokenCommand {
  186. GenerateAuth {
  187. #[clap(short, long)]
  188. client: String,
  189. #[clap(short, long)]
  190. username: String,
  191. #[clap(short, long)]
  192. scopes: String
  193. },
  194. GenerateRefresh {
  195. #[clap(short, long)]
  196. client: String,
  197. #[clap(short, long)]
  198. username: String,
  199. #[clap(short, long)]
  200. scopes: String
  201. },
  202. Inspect { token: String },
  203. }
  204. #[derive(Debug, Parser)]
  205. struct TokenArgs {
  206. #[clap(subcommand)]
  207. command: TokenCommand,
  208. }
  209. impl TokenArgs {
  210. async fn run(&self, root: &RootArgs, db: microrm::DB) {
  211. let config = config::Config::build_from(&db.query_interface(), None);
  212. match &self.command {
  213. TokenCommand::GenerateAuth { client, username, scopes } => {
  214. let qi = db.query_interface();
  215. let realm_id = qi.get().by(schema::Realm::Shortname, &root.realm).one().unwrap().expect("no such realm").id();
  216. let token = token::generate_auth_token(
  217. &config,
  218. &qi,
  219. realm_id,
  220. qi.get().by(schema::Client::Realm, &realm_id).by(schema::Client::Shortname, client.as_str()).one().unwrap().expect("no such client").id(),
  221. qi.get().by(schema::User::Realm, &realm_id).by(schema::User::Username, username.as_str()).one().unwrap().expect("no such user").id(),
  222. scopes.split_whitespace(),
  223. );
  224. if let Some(t) = token {
  225. println!("token: {t}");
  226. }
  227. else {
  228. println!("Could not generate token");
  229. }
  230. },
  231. TokenCommand::GenerateRefresh { client, username, scopes } => {
  232. },
  233. TokenCommand::Inspect { token } => {
  234. },
  235. }
  236. }
  237. }
  238. #[derive(Debug, Parser)]
  239. struct CreateUserArgs {
  240. username: String,
  241. }
  242. #[derive(Debug, Parser)]
  243. struct AuthUserArgs {
  244. username: String,
  245. #[clap(short = 'p', long, parse(from_occurrences))]
  246. change_password: usize,
  247. }
  248. #[derive(Debug, Subcommand)]
  249. enum UserCommand {
  250. List,
  251. Create(CreateUserArgs),
  252. Auth(AuthUserArgs),
  253. }
  254. #[derive(Debug, Parser)]
  255. struct UserArgs {
  256. #[clap(subcommand)]
  257. command: UserCommand,
  258. }
  259. impl UserArgs {
  260. async fn run(&self, root: &RootArgs, db: microrm::DB) {
  261. match &self.command {
  262. UserCommand::List => user_management::list(&root.realm, db),
  263. UserCommand::Create(args) => {
  264. user_management::create(&root.realm, db, args.username.as_str())
  265. }
  266. UserCommand::Auth(args) => user_management::change_auth(
  267. &root.realm,
  268. db,
  269. args.username.as_str(),
  270. args.change_password > 0,
  271. ),
  272. }
  273. }
  274. }
  275. pub fn invoked() {
  276. let args = RootArgs::parse();
  277. smol::block_on(args.run());
  278. // async_std::task::block_on(args.run());
  279. }