diff --git a/CHANGELOG-Japanese.md b/CHANGELOG-Japanese.md index 752182ab..b6e96246 100644 --- a/CHANGELOG-Japanese.md +++ b/CHANGELOG-Japanese.md @@ -4,7 +4,8 @@ **新機能:** -- 解析結果をJSONに出力する機能を追加した (`-j` と `--json-timeline` )。 (#654) (@hitenkoku) +- 解析結果をJSON形式で出力する機能を追加した (`-j` と `--json` )。 (#654) (@hitenkoku) +- 解析結果をJSONL形式で出力する機能を追加した (`-J` と `--jsonl` )。 (#694) (@hitenkoku) **改善:** diff --git a/CHANGELOG.md b/CHANGELOG.md index 27666c44..60364fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ **New Features:** -- You can now save the timeline to JSON files with the `-j, --json-timeline` option. (#654) (@hitenkoku) +- You can now save the timeline to JSON files with the `-j, --json` option. (#654) (@hitenkoku) +- You can now save the timeline to JSONL files with the `-J, --jsonl` option. (#694) (@hitenkoku) **Enhancements:** diff --git a/README-Japanese.md b/README-Japanese.md index 5b0f02aa..0cc655db 100644 --- a/README-Japanese.md +++ b/README-Japanese.md @@ -359,6 +359,7 @@ macOSの環境設定から「セキュリティとプライバシー」を開き これで実行できるようになります。 # 使用方法 + ## 主なコマンド * デフォルト: ファストフォレンジックタイムラインの作成。 @@ -389,6 +390,7 @@ ADVANCED: OUTPUT: -j, --json タイムラインの出力をJSON形式で保存する(例: -j -o results.json) + -J, --jsonl タイムラインの出力をJSONL形式で保存する (例: -J -o results.jsonl) -o, --output タイムラインをCSV形式で保存する (例: results.csv) -P, --profile 利用する出力プロファイル名を指定する (minimal, standard, verbose, verbose-all-field-info, verbose-details-and-all-field-info) diff --git a/README.md b/README.md index 4f4c10b9..e02e890d 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,7 @@ ADVANCED: OUTPUT: -j, --json Save the timeline in JSON format (ex: -j -o results.json) + -J, --jsonl Save the timeline in JSONL format (ex: -J -o results.jsonl) -o, --output Save the timeline in CSV format (ex: results.csv) -P, --profile Specify output profile (minimal, standard, verbose, verbose-all-field-info, verbose-details-and-all-field-info) diff --git a/src/afterfact.rs b/src/afterfact.rs index ff53bb9a..b8bc0ecb 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -213,8 +213,9 @@ fn emit_csv( let disp_wtr = BufferWriter::stdout(ColorChoice::Always); let mut disp_wtr_buf = disp_wtr.buffer(); let json_output_flag = configs::CONFIG.read().unwrap().args.json_timeline; + let jsonl_output_flag = configs::CONFIG.read().unwrap().args.jsonl_timeline; - let mut wtr = if json_output_flag { + let mut wtr = if json_output_flag || jsonl_output_flag { WriterBuilder::new() .delimiter(b'\n') .double_quote(false) @@ -293,8 +294,13 @@ fn emit_csv( ) .ok(); } else if json_output_flag { + // JSON output wtr.write_field(" {")?; - wtr.write_field(&output_json_str(&detect_info.ext_field, &profile))?; + wtr.write_field(&output_json_str( + &detect_info.ext_field, + &profile, + jsonl_output_flag, + ))?; if processed_message_cnt != message::MESSAGES._len() - 1 || info_idx != detect_infos.len() - 1 { @@ -302,6 +308,12 @@ fn emit_csv( } else { wtr.write_field(" }")?; } + } else if jsonl_output_flag { + // JSONL output format + wtr.write_field(format!( + "{{ {} }}", + &output_json_str(&detect_info.ext_field, &profile, jsonl_output_flag) + ))?; } else { // csv output format if plus_header { @@ -914,6 +926,7 @@ fn _convert_valid_json_str(input: &[&str], concat_flag: bool) -> String { fn output_json_str( ext_field: &LinkedHashMap, profile: &LinkedHashMap, + jsonl_output_flag: bool, ) -> String { let mut target: Vec = vec![]; for (k, v) in ext_field.iter() { @@ -1034,7 +1047,11 @@ fn output_json_str( } value.push("\n ]".to_string()); - let fmted_val = value.join(""); + let fmted_val = if jsonl_output_flag { + value.iter().map(|x| x.replace('\n', "")).join("") + } else { + value.join("") + }; target.push(_create_json_output_format( &key, &fmted_val, @@ -1043,7 +1060,13 @@ fn output_json_str( )); } } - target.join(",\n") + if jsonl_output_flag { + // JSONL output + target.into_iter().map(|x| x.replace(" ", "")).join(",") + } else { + // JSON format output + target.join(",\n") + } } #[cfg(test)] diff --git a/src/detections/configs.rs b/src/detections/configs.rs index 73392bfc..f1849a65 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -241,6 +241,10 @@ pub struct Config { #[clap(help_heading = Some("OUTPUT"), short = 'j', long = "json", requires = "output")] pub json_timeline: bool, + /// Save the timeline in JSONL format (ex: -J -o results.jsonl) + #[clap(help_heading = Some("OUTPUT"), short = 'J', long = "jsonl", requires = "output")] + pub jsonl_timeline: bool, + /// Do not display result summary #[clap(help_heading = Some("DISPLAY-SETTINGS"), long = "no-summary")] pub no_summary: bool,