commit 759be48b0e29c113f5b04f59da7dab638cb301df Author: JuliusHerrmann Date: Fri Jan 27 15:23:57 2023 +0100 default writing works diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..743ec78 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,143 @@ +use std::fs::File; +use std::io::prelude::*; +use std::process::{Command, exit}; +use clap::Parser; +use colored::*; + + +mod parser; + + +// setup cli parser +#[derive(Parser, Debug)] +#[command( + author = "Julius Herrmann (juhe00002@uni-saarland.de)", + about = "A simple tool to enable batch writing od 'sysoISIm-SJA2' cards with the corresponding CSV data by the manufacturer", + long_about = None)] +pub struct CliArgs { + /// The path to the pySim binary + #[arg(short = 'b', long = "binary", default_value_t = String::from("./pySim-prog.py"))] + bin: String, + /// The path to the csv file to read + #[arg(short = 'c', long = "csv")] + csv: String, + /// Set the output file with the commands for the core + #[arg(short = 'o', long = "output", default_value_t = String::from("output"))] + output_file: String, + /// The name of the nework + #[arg(short = 'n', long = "name")] + name: String, + /// The mcc code + #[arg(long = "mcc")] + mcc: String, + /// The mnc code + #[arg(long = "mnc")] + mnc: String, + #[arg(short = 'd', long = "device", default_value_t = 0)] + device: u8, + #[arg(long = "ki", default_value_t = String::from("00000000000000000000000000000000"))] + ki: String, + #[arg(long = "opc", default_value_t = String::from("00000000000000000000000000000000"))] + opc: String, + /// Set true if you want to use an op key instead of opc + #[arg(long = "use-op", default_value_t = false)] + use_op: bool, + #[arg(long = "op", default_value_t = String::from("00000000000000000000000000000000"))] + op: String, + /// Set true if you want to execute the "deactivate5g" script + #[arg(long = "deactivate-5g", default_value_t = false)] + deactivate5g: bool, + /// Set true to only do a dry run (print commands and not execute them) + #[arg(long = "dry-run", default_value_t = false)] + dry_run: bool, +} + +fn main() { + let args = CliArgs::parse(); + let mut user_provision_commands = vec![]; + let mut pysim_outputs = vec![]; + // parse the supplied card configs + let card_configs = parser::parse_csv(&args.csv).unwrap(); + for conf in card_configs { + // create the arguments + let imsi_ending = String::from(&conf.IMSI[6..]); + + // add command to be run on the open5gcore + user_provision_commands.push(format!("./provision_user.sh -S 001010000012345 -k {} -a 8000 -o 00000000000000000000000000000000 -s 000000000010 -t 0 -c 1 -u 0 -T 12345", String::from(&conf.IMSI))); + + let pysim_args = conf.generate_pysim_args(&args); + + println!("\n{}:", "EXECUTING".red()); + print!("{}", args.bin); + for pysim_arg in &pysim_args { + print!(" {}", pysim_arg); + } + + if !wait_for_user(&format!("Please insert the sim-card with IMSI ending in: {}", imsi_ending.green())) { + exit_programm(1); + } + + if args.dry_run { + println!("{}: The command is not executed since {} is enabled", "WARNING".yellow(), "dry_run".yellow()); + } else { + let mut command = Command::new(&args.bin); + for pysim_arg in pysim_args { + command.arg(pysim_arg); + } + // wait for the child process to stop + // let child = command.stdout(Stdio::piped()).spawn().unwrap(); + // let output = child.wait_with_output().unwrap(); + let output = command.output().expect("process failed to execute"); + if output.status.success() { + let output_string = String::from_utf8(output.stdout).unwrap(); + pysim_outputs.push(output_string.clone()); + println!("{} ", output_string); + println!("{} programmed sim card", "SUCCESSFULLY".green()); + } else { + println!("{} ", String::from_utf8(output.stderr).unwrap()); + println!("{}, please check the output of pySim above!", "ERROR".red()); + continue; + } + } + + // possibly execute deactivate5g command + if args.deactivate5g { + println!("{}: ./pySim-shell.py -p{} --script scripts/deactivate-5g.script", "EXECUTING".red(), &args.device); + if args.dry_run { + print!("{}: The command is not executed since {} is enabled\n", "WARNING".yellow(), "dry_run".yellow()); + continue; + } + println!("{}. Not Implemented Yet!", "TODO".red()); + } + } + + // output to file + let mut file = File::create(args.output_file).unwrap(); + writeln!(&mut file, "PySim outputs:").unwrap(); + for pysim_out in pysim_outputs { + writeln!(&mut file, "{}", pysim_out).unwrap(); + } + writeln!(&mut file, "\nCommands to be executed on core:").unwrap(); + for command in user_provision_commands { + writeln!(&mut file, "{}", command).unwrap(); + } + exit_programm(0) +} + +fn exit_programm(code: i32) -> () { + println!("{}", "GOODBYE!".green()); + exit(code); +} + +// wait for user to input enter. If a is entered return false signaling to stop the program +fn wait_for_user(msg: &str) -> bool { + println!("\n{}\nPress enter to continue or 'a' to abort:", msg); + let mut next_string = String::new(); + match std::io::stdin().read_line(&mut next_string) { + Ok(n) if n > 0 => { + return 'a' != next_string.chars().next().unwrap() + } + Ok(_) => return true, // other input is ignored + Err(err) => panic!("{}", err), + }; +} diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..640670e --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,118 @@ +use std::error::Error; +use std::io::{self, BufRead}; +use std::fs::File; +use std::path::Path; + +use csv::StringRecord; +use serde::Deserialize; + +use crate::CliArgs; + + +#[derive(Deserialize, Debug)] +// disable compiler warnings as this is just a struct to save data as it is in csv data +#[allow(dead_code, non_snake_case)] +pub struct CardValues { + pub IMSI: String, + ICCID: String, + ACC: String, + PIN1: String, + PUK1: String, + PIN2: String, + PUK2: String, + Ki: String, + OPC: String, + ADM1: String, + KIC1: String, + KID1: String, + KIK1: String, + KIC2: String, + KID2: String, + KIK2: String, + KIC3: String, + KID3: String, + KIK3: String, +} + +impl CardValues { + pub fn generate_pysim_args(self, args: &CliArgs) -> Vec { + // calculate new imsi + let new_imsi: &String = &format!("--imsi={}{}{}", + args.mnc, + args.mcc, + &self.IMSI[(args.mnc.len() + args.mcc.len())..] + ); + let p = format!("-p{}", args.device); + let name = format!("--name=\"{}\"", args.name); + let mnc = format!("--mnc={}", args.mnc); + let mcc = format!("--mcc={}", args.mcc); + let iccid = format!("--iccid={}", self.ICCID); + let pin_adm = format!("--pin-adm={}", self.ADM1); + let ki = format!("--ki={}", args.ki); + if args.use_op { + let op = format!("--op={}", args.op); + vec![ + p, + new_imsi.to_string(), + name, + mnc, + mcc, + iccid, + pin_adm, + ki, + op + ] + } else { + let opc = format!("--opc={}", args.opc); + vec![ + p, + new_imsi.to_string(), + name, + mnc, + mcc, + iccid, + pin_adm, + ki, + opc + ] + } + } +} + +pub fn parse_csv(path: &str) -> Result, Box> { + // // Build the CSV reader and iterate over each record. + // let mut rdr = csv::Reader::from_reader(io::stdin()); + // let header = rdr.records().next().unwrap().unwrap(); + // println!("{:?}", header); + // for result in rdr.records().skip(1) { + // let sim_conf: CardValues = result.unwrap().deserialize(Some(&header)).unwrap(); + // println!("{:?}", sim_conf); + // } + if let Ok(mut lines) = read_lines(path) { + let first_line = &lines.next().unwrap().unwrap(); + let first_line = first_line.replace(" ", ""); + //split the first line into a vec + let first_line: Vec<&str> = first_line.split(",").collect(); + let header = StringRecord::from(first_line); + // now we got the header. Continue to deserialize every other line + Ok(lines.map(|line| { + // unpack line + let line = line.unwrap(); + let line = line.replace(" ", ""); + let line: Vec<&str> = line.split(",").collect(); + let record = StringRecord::from(line); + let sim_conf: CardValues = record.deserialize(Some(&header)).unwrap(); + sim_conf + }).collect()) + } else { + panic!("could not read csv"); + } +} + +// The output is wrapped in a Result to allow matching on errors +// Returns an Iterator to the Reader of the lines of the file. +fn read_lines

(filename: P) -> io::Result>> +where P: AsRef, { + let file = File::open(filename)?; + Ok(io::BufReader::new(file).lines()) +}