default writing works
This commit is contained in:
commit
759be48b0e
143
src/main.rs
Normal file
143
src/main.rs
Normal file
@ -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),
|
||||||
|
};
|
||||||
|
}
|
||||||
118
src/parser.rs
Normal file
118
src/parser.rs
Normal file
@ -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<String> {
|
||||||
|
// 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<Vec<CardValues>, Box<dyn Error>> {
|
||||||
|
// // 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<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||||
|
where P: AsRef<Path>, {
|
||||||
|
let file = File::open(filename)?;
|
||||||
|
Ok(io::BufReader::new(file).lines())
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user