Compare commits
No commits in common. "58ef806e56d5d42d504e5e776333e989ffd9dc8f" and "e469f7593a60e87bc592ee53b0e8573583da6d08" have entirely different histories.
58ef806e56
...
e469f7593a
|
@ -5,8 +5,8 @@ Goal - a commandline-based tool for creating blocklists for ActivityPub software
|
|||
## Planned features
|
||||
|
||||
- [ ] Accept and parse commandline arguments
|
||||
- [ ] Create tiered or thresholded lists
|
||||
- [ ] Support CSV and JSON
|
||||
- [ ] Add ability to specify reasons
|
||||
- [ ] Use URLs as sources
|
||||
- [ ] Directly request lists from API endpoints
|
||||
- [ ] Add ability to specify reasons
|
||||
- [ ] Create tiered or thresholded lists
|
||||
- [ ] Support CSV and JSON
|
13
src/main.rs
13
src/main.rs
|
@ -22,10 +22,6 @@ struct Cli {
|
|||
#[arg(short = 'M', long)]
|
||||
mute: Vec<PathBuf>,
|
||||
|
||||
/// Specifies a source (*.block.txt, *.mute.txt)
|
||||
#[arg(short = 'S', long)]
|
||||
src: Vec<PathBuf>,
|
||||
|
||||
/// Specifies confidence in a source. Default = 100
|
||||
#[arg(short, long)]
|
||||
trust: Vec<u16>,
|
||||
|
@ -38,7 +34,7 @@ struct Cli {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init(); // TODO add more logging
|
||||
env_logger::init();
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
@ -46,9 +42,6 @@ fn main() {
|
|||
error!("No lists or configuration provided.");
|
||||
}
|
||||
|
||||
// TODO parse config file if one is provided
|
||||
|
||||
// TODO read modsources from files
|
||||
// TODO combine modsources into modmap
|
||||
// TODO write modmap to files
|
||||
// TODO argument parsing - IN PROGRESS
|
||||
// TODO logging
|
||||
}
|
||||
|
|
82
src/manip.rs
82
src/manip.rs
|
@ -4,35 +4,35 @@ use log::error;
|
|||
|
||||
// ENUMS
|
||||
|
||||
/// Specifies a limit type, whether block or silence
|
||||
/// Specifies a moderation action, whether block or silence
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Limit {
|
||||
pub enum ModAction {
|
||||
Block,
|
||||
Silence,
|
||||
}
|
||||
|
||||
// STRUCTS
|
||||
|
||||
/// Wraps a host's weighted limits
|
||||
/// Indicates weight of moderation action on a host
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
pub struct LimitIndices {
|
||||
pub struct ModActionTrust {
|
||||
pub block: u16,
|
||||
pub silence: u16,
|
||||
}
|
||||
|
||||
impl LimitIndices {
|
||||
pub fn add_limit(&mut self, limit: Limit, weight: u16) -> &mut Self {
|
||||
match limit {
|
||||
Limit::Block => self.block += weight,
|
||||
Limit::Silence => self.silence += weight,
|
||||
impl ModActionTrust {
|
||||
pub fn add_action(&mut self, action: ModAction, trust: u16) -> &mut Self {
|
||||
match action {
|
||||
ModAction::Block => self.block += trust,
|
||||
ModAction::Silence => self.silence += trust,
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(u16, u16)> for LimitIndices {
|
||||
/// Creates indices from a tuple of two `u16` weights. Useful mostly for
|
||||
/// testing.
|
||||
impl From<(u16, u16)> for ModActionTrust {
|
||||
/// Creates mod action weights from a tuple of two `u16` weights. Useful
|
||||
/// mostly for testing.
|
||||
fn from(value: (u16, u16)) -> Self {
|
||||
Self {
|
||||
block: value.0,
|
||||
|
@ -41,69 +41,67 @@ impl From<(u16, u16)> for LimitIndices {
|
|||
}
|
||||
}
|
||||
|
||||
/// Contains a mapping of hosts to limits as well as a trust value which is
|
||||
/// used to weight limits when building a merged list
|
||||
/// Contains a mapping of hosts to moderation actions as well as a trust value,
|
||||
/// which is used to weight moderation actions when building a mod map
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct LimitList {
|
||||
pub limits: HashMap<String, Limit>,
|
||||
pub struct ModSource {
|
||||
pub actions: HashMap<String, ModAction>,
|
||||
pub trust: u16,
|
||||
}
|
||||
|
||||
impl Default for LimitList {
|
||||
impl Default for ModSource {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
limits: HashMap::new(),
|
||||
actions: HashMap::new(),
|
||||
trust: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HashMap<String, Limit>> for LimitList {
|
||||
fn from(map: HashMap<String, Limit>) -> Self {
|
||||
impl From<HashMap<String, ModAction>> for ModSource {
|
||||
fn from(map: HashMap<String, ModAction>) -> Self {
|
||||
Self {
|
||||
limits: map,
|
||||
actions: map,
|
||||
trust: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LimitList {
|
||||
fn add_host(&mut self, host: &str, limit: Limit) -> &mut Self {
|
||||
self.limits.insert(host.to_string(), limit);
|
||||
impl ModSource {
|
||||
fn add_action(&mut self, host: &str, action: ModAction) -> &mut Self {
|
||||
self.actions.insert(host.to_string(), action);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(map: HashMap<String, Limit>, trust: u16) -> Self {
|
||||
pub fn build(map: HashMap<String, ModAction>, trust: u16) -> Self {
|
||||
let mut src = Self::from(map);
|
||||
src.trust = trust;
|
||||
src
|
||||
}
|
||||
|
||||
pub fn import_file(&mut self, path: &str, limit: Limit) -> &mut Self {
|
||||
pub fn import_file(&mut self, path: &str, action: ModAction) -> &mut Self {
|
||||
let contents = fs::read_to_string(path).unwrap();
|
||||
for host in contents.lines().filter(|line| !line.is_empty()) {
|
||||
self.add_host(host, limit);
|
||||
self.add_action(host, action);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A map of hosts (as strings) to their limit weights
|
||||
/// A map of hosts (as strings) to weighted mod actions
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
pub struct MergedLimitList {
|
||||
pub map: HashMap<String, LimitIndices>,
|
||||
pub max: u16,
|
||||
}
|
||||
pub struct ModMap(pub HashMap<String, ModActionTrust>);
|
||||
|
||||
impl MergedLimitList {
|
||||
pub fn add_limit_list(&mut self, src: LimitList) -> &mut Self {
|
||||
for (host, limit) in src.limits.into_iter() {
|
||||
let entry = self.map.entry(host).or_default();
|
||||
entry.add_limit(limit, src.trust);
|
||||
impl ModMap {
|
||||
pub fn add_source(&mut self, src: ModSource) -> &mut Self {
|
||||
let items = src.actions.into_iter();
|
||||
|
||||
for (host, action) in items {
|
||||
let entry = self.0.entry(host).or_default();
|
||||
entry.add_action(action, src.trust);
|
||||
}
|
||||
|
||||
self.max += src.trust;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -111,18 +109,18 @@ impl MergedLimitList {
|
|||
self,
|
||||
block_path: &str,
|
||||
mute_path: &str,
|
||||
indices: (u16, u16),
|
||||
heat: (u16, u16),
|
||||
) -> std::io::Result<()> {
|
||||
if self.map.is_empty() {
|
||||
if self.0.is_empty() {
|
||||
error!("Nothing to export!");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (block_thresh, mute_thresh) = indices;
|
||||
let (block_thresh, mute_thresh) = heat;
|
||||
let mut block_output: String = String::default();
|
||||
let mut mute_output: String = String::default();
|
||||
|
||||
for item in self.map.into_iter() {
|
||||
for item in self.0.into_iter() {
|
||||
let (block_trust, mute_trust) = (item.1.block, item.1.silence);
|
||||
|
||||
if block_trust >= block_thresh {
|
||||
|
|
|
@ -5,13 +5,13 @@ use std::{collections::HashMap, fs};
|
|||
use crate::manip::*;
|
||||
|
||||
#[test]
|
||||
fn limit_add() {
|
||||
let mut at = LimitIndices::default();
|
||||
fn modaction_add() {
|
||||
let mut at = ModActionTrust::default();
|
||||
|
||||
at.add_limit(Limit::Block, 123)
|
||||
.add_limit(Limit::Silence, 456);
|
||||
at.add_action(ModAction::Block, 123)
|
||||
.add_action(ModAction::Silence, 456);
|
||||
|
||||
let test_at = LimitIndices {
|
||||
let test_at = ModActionTrust {
|
||||
block: 123,
|
||||
silence: 456,
|
||||
};
|
||||
|
@ -20,14 +20,14 @@ fn limit_add() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn limit_combine() {
|
||||
let mut at = LimitIndices::default();
|
||||
fn modaction_combine() {
|
||||
let mut at = ModActionTrust::default();
|
||||
|
||||
at.add_limit(Limit::Block, 123)
|
||||
.add_limit(Limit::Block, 333)
|
||||
.add_limit(Limit::Silence, 123);
|
||||
at.add_action(ModAction::Block, 123)
|
||||
.add_action(ModAction::Block, 333)
|
||||
.add_action(ModAction::Silence, 123);
|
||||
|
||||
let test_at = LimitIndices {
|
||||
let test_at = ModActionTrust {
|
||||
block: 456,
|
||||
silence: 123,
|
||||
};
|
||||
|
@ -36,19 +36,19 @@ fn limit_combine() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn limitlist_from_map() {
|
||||
let src1 = LimitList::from(HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.net"), Limit::Block),
|
||||
fn modsource_from_map() {
|
||||
let src1 = ModSource::from(HashMap::from([
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
(String::from("example.net"), ModAction::Block),
|
||||
]));
|
||||
|
||||
assert_eq!(
|
||||
src1.limits,
|
||||
src1.actions,
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.net"), Limit::Block),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
(String::from("example.net"), ModAction::Block),
|
||||
])
|
||||
);
|
||||
|
||||
|
@ -56,133 +56,139 @@ fn limitlist_from_map() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn limitlist_from_map_and_trust() {
|
||||
let src2 = LimitList::build(
|
||||
fn modsource_from_map_and_trust() {
|
||||
let src2 = ModSource::build(
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.net"), Limit::Block),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
(String::from("example.net"), ModAction::Block),
|
||||
]),
|
||||
123,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
src2.limits,
|
||||
src2.actions,
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.net"), Limit::Block),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
(String::from("example.net"), ModAction::Block),
|
||||
])
|
||||
);
|
||||
assert_eq!(src2.trust, 123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn limitlist_from_file() {
|
||||
let mut src = LimitList::default();
|
||||
src.import_file("test/example_blocklist.txt", Limit::Block)
|
||||
.import_file("test/example_mutelist.txt", Limit::Silence);
|
||||
fn modsource_from_file() {
|
||||
let mut src = ModSource::default();
|
||||
src.import_file("test/example_blocklist.txt", ModAction::Block)
|
||||
.import_file("test/example_mutelist.txt", ModAction::Silence);
|
||||
|
||||
let test_src = LimitList::from(HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Block),
|
||||
(String::from("example.net"), Limit::Silence),
|
||||
let test_src = ModSource::from(HashMap::from([
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Block),
|
||||
(String::from("example.net"), ModAction::Silence),
|
||||
]));
|
||||
|
||||
assert_eq!(test_src, src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mergedlist_from_limitlist() {
|
||||
let mut ml = MergedLimitList::default();
|
||||
fn modmap_from_modsource() {
|
||||
let mut ml = ModMap::default();
|
||||
|
||||
let src1 = LimitList::from(HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.net"), Limit::Block),
|
||||
let src1 = ModSource::from(HashMap::from([
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
(String::from("example.net"), ModAction::Block),
|
||||
]));
|
||||
|
||||
let mut src2 = LimitList::default();
|
||||
src2.import_file("test/example_blocklist.txt", Limit::Block)
|
||||
.import_file("test/example_mutelist.txt", Limit::Silence);
|
||||
let mut src2 = ModSource::default();
|
||||
src2.import_file("test/example_blocklist.txt", ModAction::Block)
|
||||
.import_file("test/example_mutelist.txt", ModAction::Silence);
|
||||
|
||||
ml.add_limit_list(src1).add_limit_list(src2);
|
||||
ml.add_source(src1).add_source(src2);
|
||||
|
||||
let test_ml = MergedLimitList {
|
||||
map: HashMap::from([
|
||||
(String::from("example.com"), LimitIndices::from((200, 0))),
|
||||
(String::from("example.org"), LimitIndices::from((100, 100))),
|
||||
(String::from("example.net"), LimitIndices::from((100, 100))),
|
||||
]),
|
||||
max: 200,
|
||||
};
|
||||
let test_ml = ModMap(HashMap::from([
|
||||
(String::from("example.com"), ModActionTrust::from((200, 0))),
|
||||
(
|
||||
String::from("example.org"),
|
||||
ModActionTrust::from((100, 100)),
|
||||
),
|
||||
(
|
||||
String::from("example.net"),
|
||||
ModActionTrust::from((100, 100)),
|
||||
),
|
||||
]));
|
||||
|
||||
assert_eq!(ml, test_ml);
|
||||
|
||||
let src3 = LimitList::build(
|
||||
let src3 = ModSource::build(
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
]),
|
||||
200,
|
||||
);
|
||||
|
||||
let src4 = LimitList::build(
|
||||
let src4 = ModSource::build(
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.net"), Limit::Silence),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.net"), ModAction::Silence),
|
||||
]),
|
||||
50,
|
||||
);
|
||||
|
||||
ml.add_limit_list(src3).add_limit_list(src4);
|
||||
ml.add_source(src3).add_source(src4);
|
||||
|
||||
let test_ml = MergedLimitList {
|
||||
map: HashMap::from([
|
||||
(String::from("example.com"), LimitIndices::from((450, 0))),
|
||||
(String::from("example.org"), LimitIndices::from((100, 300))),
|
||||
(String::from("example.net"), LimitIndices::from((100, 150))),
|
||||
]),
|
||||
max: 450,
|
||||
};
|
||||
let test_ml = ModMap(HashMap::from([
|
||||
(String::from("example.com"), ModActionTrust::from((450, 0))),
|
||||
(
|
||||
String::from("example.org"),
|
||||
ModActionTrust::from((100, 300)),
|
||||
),
|
||||
(
|
||||
String::from("example.net"),
|
||||
ModActionTrust::from((100, 150)),
|
||||
),
|
||||
]));
|
||||
|
||||
assert_eq!(ml, test_ml);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mergedlist_export_txt() {
|
||||
let mut ml = MergedLimitList::default();
|
||||
fn modmap_export_txt() {
|
||||
let mut ml = ModMap::default();
|
||||
|
||||
let src1 = LimitList::from(HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.net"), Limit::Block),
|
||||
let src1 = ModSource::from(HashMap::from([
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
(String::from("example.net"), ModAction::Block),
|
||||
]));
|
||||
|
||||
let mut src2 = LimitList::default();
|
||||
src2.import_file("test/example_blocklist.txt", Limit::Block)
|
||||
.import_file("test/example_mutelist.txt", Limit::Silence);
|
||||
let mut src2 = ModSource::default();
|
||||
src2.import_file("test/example_blocklist.txt", ModAction::Block)
|
||||
.import_file("test/example_mutelist.txt", ModAction::Silence);
|
||||
|
||||
let src3 = LimitList::build(
|
||||
let src3 = ModSource::build(
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.org"), Limit::Silence),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.org"), ModAction::Silence),
|
||||
]),
|
||||
200,
|
||||
);
|
||||
|
||||
let src4 = LimitList::build(
|
||||
let src4 = ModSource::build(
|
||||
HashMap::from([
|
||||
(String::from("example.com"), Limit::Block),
|
||||
(String::from("example.net"), Limit::Silence),
|
||||
(String::from("example.com"), ModAction::Block),
|
||||
(String::from("example.net"), ModAction::Silence),
|
||||
]),
|
||||
50,
|
||||
);
|
||||
|
||||
ml.add_limit_list(src1)
|
||||
.add_limit_list(src2)
|
||||
.add_limit_list(src3)
|
||||
.add_limit_list(src4);
|
||||
ml.add_source(src1)
|
||||
.add_source(src2)
|
||||
.add_source(src3)
|
||||
.add_source(src4);
|
||||
|
||||
let _ = ml.export_file("test/test_blocks.txt", "test/test_mutes.txt", (200, 150));
|
||||
|
||||
|
|
Loading…
Reference in a new issue