├── README.md ├── fuzz ├── .gitignore └── _examples ├── rustfmt.toml ├── sectxtlib ├── resources │ └── test │ │ ├── .gitattributes │ │ ├── gen_unsigned │ │ ├── gen_unsigned_0025.stxt │ │ ├── gen_unsigned_0029.stxt │ │ ├── gen_unsigned_0062.stxt │ │ ├── gen_unsigned_0067.stxt │ │ ├── gen_unsigned_0013.stxt │ │ ├── gen_unsigned_0051.stxt │ │ ├── gen_unsigned_0002.stxt │ │ ├── gen_unsigned_0035.stxt │ │ ├── gen_unsigned_0046.stxt │ │ ├── gen_unsigned_0055.stxt │ │ ├── gen_unsigned_0061.stxt │ │ ├── gen_unsigned_0087.stxt │ │ ├── gen_unsigned_0006.stxt │ │ ├── gen_unsigned_0063.stxt │ │ ├── gen_unsigned_0092.stxt │ │ ├── gen_unsigned_0056.stxt │ │ ├── gen_unsigned_0099.stxt │ │ ├── gen_unsigned_0008.stxt │ │ ├── gen_unsigned_0012.stxt │ │ ├── gen_unsigned_0068.stxt │ │ ├── gen_unsigned_0001.stxt │ │ ├── gen_unsigned_0024.stxt │ │ ├── gen_unsigned_0034.stxt │ │ ├── gen_unsigned_0060.stxt │ │ ├── gen_unsigned_0089.stxt │ │ ├── gen_unsigned_0078.stxt │ │ ├── gen_unsigned_0033.stxt │ │ ├── gen_unsigned_0091.stxt │ │ ├── gen_unsigned_0095.stxt │ │ ├── gen_unsigned_0036.stxt │ │ ├── gen_unsigned_0044.stxt │ │ ├── gen_unsigned_0005.stxt │ │ ├── gen_unsigned_0018.stxt │ │ ├── gen_unsigned_0043.stxt │ │ ├── gen_unsigned_0017.stxt │ │ ├── gen_unsigned_0045.stxt │ │ ├── gen_unsigned_0079.stxt │ │ ├── gen_unsigned_0100.stxt │ │ ├── gen_unsigned_0015.stxt │ │ ├── gen_unsigned_0041.stxt │ │ ├── gen_unsigned_0085.stxt │ │ ├── gen_unsigned_0027.stxt │ │ ├── gen_unsigned_0071.stxt │ │ ├── gen_unsigned_0080.stxt │ │ ├── gen_unsigned_0019.stxt │ │ ├── gen_unsigned_0022.stxt │ │ ├── gen_unsigned_0052.stxt │ │ ├── gen_unsigned_0023.stxt │ │ ├── gen_unsigned_0064.stxt │ │ ├── gen_unsigned_0072.stxt │ │ ├── gen_unsigned_0097.stxt │ │ ├── gen_unsigned_0009.stxt │ │ ├── gen_unsigned_0014.stxt │ │ ├── gen_unsigned_0048.stxt │ │ ├── gen_unsigned_0050.stxt │ │ ├── gen_unsigned_0069.stxt │ │ ├── gen_unsigned_0081.stxt │ │ ├── gen_unsigned_0026.stxt │ │ ├── gen_unsigned_0040.stxt │ │ ├── gen_unsigned_0049.stxt │ │ ├── gen_unsigned_0090.stxt │ │ ├── gen_unsigned_0096.stxt │ │ ├── gen_unsigned_0028.stxt │ │ ├── gen_unsigned_0032.stxt │ │ ├── gen_unsigned_0021.stxt │ │ ├── gen_unsigned_0054.stxt │ │ ├── gen_unsigned_0070.stxt │ │ ├── gen_unsigned_0004.stxt │ │ ├── gen_unsigned_0011.stxt │ │ ├── gen_unsigned_0088.stxt │ │ ├── gen_unsigned_0076.stxt │ │ ├── gen_unsigned_0010.stxt │ │ ├── gen_unsigned_0039.stxt │ │ ├── gen_unsigned_0086.stxt │ │ ├── gen_unsigned_0059.stxt │ │ ├── gen_unsigned_0093.stxt │ │ ├── gen_unsigned_0094.stxt │ │ ├── gen_unsigned_0042.stxt │ │ ├── gen_unsigned_0082.stxt │ │ ├── gen_unsigned_0077.stxt │ │ ├── gen_unsigned_0003.stxt │ │ ├── gen_unsigned_0065.stxt │ │ ├── gen_unsigned_0098.stxt │ │ ├── gen_unsigned_0038.stxt │ │ ├── gen_unsigned_0073.stxt │ │ ├── gen_unsigned_0083.stxt │ │ ├── gen_unsigned_0031.stxt │ │ ├── gen_unsigned_0053.stxt │ │ ├── gen_unsigned_0058.stxt │ │ ├── gen_unsigned_0057.stxt │ │ ├── gen_unsigned_0016.stxt │ │ ├── gen_unsigned_0030.stxt │ │ ├── gen_unsigned_0020.stxt │ │ ├── gen_unsigned_0007.stxt │ │ ├── gen_unsigned_0074.stxt │ │ ├── gen_unsigned_0075.stxt │ │ ├── gen_unsigned_0037.stxt │ │ ├── gen_unsigned_0084.stxt │ │ ├── gen_unsigned_0047.stxt │ │ └── gen_unsigned_0066.stxt │ │ ├── valid_unsigned │ │ ├── github_com.stxt │ │ ├── rfc_unsigned.stxt │ │ ├── www_gov_uk.stxt │ │ └── wordpress_org.stxt │ │ └── valid_signed │ │ ├── securitytxt_org.stxt │ │ ├── rfc_signed.stxt │ │ ├── redhat.stxt │ │ └── opera_com.stxt ├── src │ ├── raw_field.rs │ ├── securitytxt_options.rs │ ├── parse_error.rs │ ├── securitytxt.rs │ ├── fields.rs │ ├── parsers.rs │ ├── lib.rs │ └── pgpcleartextmessage.rs ├── Cargo.toml └── README.md ├── .cargo └── config.toml ├── rust-toolchain.toml ├── sectxtbin ├── src │ ├── status.rs │ ├── settings.rs │ ├── network.rs │ ├── website.rs │ └── main.rs ├── Cargo.toml └── README.md ├── Cargo.toml ├── sectxtfuzz ├── src │ └── main.rs └── Cargo.toml ├── .editorconfig ├── .github └── workflows │ ├── trufflehog.yaml │ └── main.yml ├── .gitignore ├── scripts ├── checktop500 └── checkalexa1m ├── .vscode └── tasks.json ├── LICENSE ├── Makefile └── Cargo.lock /README.md: -------------------------------------------------------------------------------- 1 | sectxtbin/README.md -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | */ 2 | !_examples/ 3 | -------------------------------------------------------------------------------- /fuzz/_examples: -------------------------------------------------------------------------------- 1 | ../sectxtlib/resources/test/valid -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | max_width = 120 3 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/.gitattributes: -------------------------------------------------------------------------------- 1 | *.stxt binary 2 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["--cfg", "tracing_unstable"] 3 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "stable" 3 | components = [ "clippy", "rustfmt" ] 4 | -------------------------------------------------------------------------------- /sectxtbin/src/status.rs: -------------------------------------------------------------------------------- 1 | pub struct Status { 2 | pub domain: String, 3 | pub available: bool, 4 | } 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | resolver = "2" 4 | members = [ 5 | "sectxtbin", 6 | "sectxtfuzz", 7 | "sectxtlib", 8 | ] 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0025.stxt: -------------------------------------------------------------------------------- 1 | COnTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | ExpiREs: 2030-04-12T23:20:50.52Z 3 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0029.stxt: -------------------------------------------------------------------------------- 1 | COntAct: https://www.rfc-editor.org/rfc/rfc3986 2 | exPiReS: 2030-04-12T23:20:50.52Z 3 | 4 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0062.stxt: -------------------------------------------------------------------------------- 1 | cOntaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | exPiRes: 2030-04-12T23:20:50.52Z 3 | 4 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0067.stxt: -------------------------------------------------------------------------------- 1 | 2 | cONTaCt: https://www.rfc-editor.org/rfc/rfc3986 3 | eXPiRES: 2030-04-12T23:20:50.52Z 4 | -------------------------------------------------------------------------------- /sectxtlib/src/raw_field.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq)] 2 | pub(crate) struct RawField<'a> { 3 | pub name: &'a str, 4 | pub value: &'a str, 5 | } 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0013.stxt: -------------------------------------------------------------------------------- 1 | coNtacT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXPirEs: 2030-04-12T23:20:50.52Z 3 | #𐥘b񫌄 4 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0051.stxt: -------------------------------------------------------------------------------- 1 | ConTaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | exPireS: 2030-04-12T23:20:50.52Z 3 | 4 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0002.stxt: -------------------------------------------------------------------------------- 1 | CoNTaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | EXPires: 2030-04-12T23:20:50.52Z 3 | ## 4 | 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0035.stxt: -------------------------------------------------------------------------------- 1 | CONTAcT: https://www.rfc-editor.org/rfc/rfc3986 2 | EXpiRes: 2030-04-12T23:20:50.52Z 3 | 4 | # 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0046.stxt: -------------------------------------------------------------------------------- 1 | cONtact: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | expIrEs: 2030-04-12T23:20:50.52Z 4 | 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0055.stxt: -------------------------------------------------------------------------------- 1 | .*!W: 2 | cONtACT: https://www.rfc-editor.org/rfc/rfc3986 3 | exPIreS: 2030-04-12T23:20:50.52Z 4 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0061.stxt: -------------------------------------------------------------------------------- 1 | cOnTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | eXPIrEs: 2030-04-12T23:20:50.52Z 4 | # 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0087.stxt: -------------------------------------------------------------------------------- 1 | cONtaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpiRES: 2030-04-12T23:20:50.52Z 3 | 4 | 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0006.stxt: -------------------------------------------------------------------------------- 1 | conTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | exPIREs: 2030-04-12T23:20:50.52Z 3 | 4 | 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0063.stxt: -------------------------------------------------------------------------------- 1 | ConTaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | ExPiREs: 2030-04-12T23:20:50.52Z 3 | #𩛞 򿷏󨸨4 4 | # 񝻘 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0092.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cONTACt: https://www.rfc-editor.org/rfc/rfc3986 5 | EXPIRES: 2030-04-12T23:20:50.52Z 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0056.stxt: -------------------------------------------------------------------------------- 1 | CoNTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | EXPiRES: 2030-04-12T23:20:50.52Z 3 | PReFERRED-lAnGUAGEs: fr 4 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0099.stxt: -------------------------------------------------------------------------------- 1 | ConTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | ExPirEs: 2030-04-12T23:20:50.52Z 3 | # 4 | 5 | # 6 | 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0008.stxt: -------------------------------------------------------------------------------- 1 | ConTaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpiReS: 2030-04-12T23:20:50.52Z 3 | 4 | pREferReD-LanGuAgES: fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0012.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 4 | CONTACt: https://www.rfc-editor.org/rfc/rfc3986 5 | 6 | # 7 | ExpIrES: 2030-04-12T23:20:50.52Z 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0068.stxt: -------------------------------------------------------------------------------- 1 | #򮬚 2 | cOntaCt: https://www.rfc-editor.org/rfc/rfc3986 3 | eXpiRES: 2030-04-12T23:20:50.52Z 4 | # 5 | 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0001.stxt: -------------------------------------------------------------------------------- 1 | cONTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | ExpIReS: 2030-04-12T23:20:50.52Z 3 | 4 | prEFerrEd-LanguageS: fr ,fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0024.stxt: -------------------------------------------------------------------------------- 1 | 2 | CoNTACT: https://www.rfc-editor.org/rfc/rfc3986 3 | ExPireS: 2030-04-12T23:20:50.52Z 4 | preFerrEd-languagEs: fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0034.stxt: -------------------------------------------------------------------------------- 1 | # 2 | cOnTaCT: https://www.rfc-editor.org/rfc/rfc3986 3 | # 4 | EXPirEs: 2030-04-12T23:20:50.52Z 5 | 6 | 7 | # 8 | 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0060.stxt: -------------------------------------------------------------------------------- 1 | # 2 | cONtAct: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | eXPIreS: 2030-04-12T23:20:50.52Z 5 | PrEFeRrEd-LANGuAgEs: fr 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0089.stxt: -------------------------------------------------------------------------------- 1 | contACt: https://www.rfc-editor.org/rfc/rfc3986 2 | eXPireS: 2030-04-12T23:20:50.52Z 3 | # x 4 | 5 | 6 | ##Ta딲򟒼 7 | 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0078.stxt: -------------------------------------------------------------------------------- 1 | 2 | Contact: https://www.rfc-editor.org/rfc/rfc3986 3 | expIREs: 2030-04-12T23:20:50.52Z 4 | PrEFeRRED-LangUAGeS: fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0033.stxt: -------------------------------------------------------------------------------- 1 | 2 | coNtACT: https://www.rfc-editor.org/rfc/rfc3986 3 | exPiRes: 2030-04-12T23:20:50.52Z 4 | PreFeRREd-lAnguaGES: fr ,fr ,fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0091.stxt: -------------------------------------------------------------------------------- 1 | conTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpIrES: 2030-04-12T23:20:50.52Z 3 | 4 | PrEFERREd-LaNGuAgES: fr , fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0095.stxt: -------------------------------------------------------------------------------- 1 | cOnTaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | EXPireS: 2030-04-12T23:20:50.52Z 3 | pREFerRed-LaNGUaGes: fr ,fr,fr 4 | 5 | 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0036.stxt: -------------------------------------------------------------------------------- 1 | contacT: https://www.rfc-editor.org/rfc/rfc3986 2 | #0p: QI 3 | EXpires: 2030-04-12T23:20:50.52Z 4 | pREFErRed-LAnguaGEs: fr 5 | # 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0044.stxt: -------------------------------------------------------------------------------- 1 | 2 | # 3 | cONtACT: https://www.rfc-editor.org/rfc/rfc3986 4 | ExpiREs: 2030-04-12T23:20:50.52Z 5 | PREfErred-LaNguaGES: fr ,fr 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0005.stxt: -------------------------------------------------------------------------------- 1 | cONtACT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpIRes: 2030-04-12T23:20:50.52Z 3 | 4 | HiRiNg: https://www.rfc-editor.org/rfc/rfc3986 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0018.stxt: -------------------------------------------------------------------------------- 1 | 2 | COntAct: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | ExpIrES: 2030-04-12T23:20:50.52Z 5 | POlIcy: https://www.rfc-editor.org/rfc/rfc3986 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0043.stxt: -------------------------------------------------------------------------------- 1 | CONtaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | EXpIRes: 2030-04-12T23:20:50.52Z 4 | 5 | pREFeRred-LaNGUAgeS: fr,fr , fr 6 | 7 | 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0017.stxt: -------------------------------------------------------------------------------- 1 | conTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | conTACT: https://www.rfc-editor.org/rfc/rfc3986 3 | expiRES: 2030-04-12T23:20:50.52Z 4 | 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0045.stxt: -------------------------------------------------------------------------------- 1 | CONtact: https://www.rfc-editor.org/rfc/rfc3986 2 | ExPireS: 2030-04-12T23:20:50.52Z 3 | CANoniCAl: https://www.rfc-editor.org/rfc/rfc3986 4 | 5 | 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0079.stxt: -------------------------------------------------------------------------------- 1 | 2 | CoNtACT: https://www.rfc-editor.org/rfc/rfc3986 3 | ExPIrEs: 2030-04-12T23:20:50.52Z 4 | 5 | # 6 | hiRINg: https://www.rfc-editor.org/rfc/rfc3986 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0100.stxt: -------------------------------------------------------------------------------- 1 | ContaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | CoNTAct: https://www.rfc-editor.org/rfc/rfc3986 3 | eXPIREs: 2030-04-12T23:20:50.52Z 4 | 5 | # 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0015.stxt: -------------------------------------------------------------------------------- 1 | CoNtAct: https://www.rfc-editor.org/rfc/rfc3986 2 | AcKNOWLEdGMeNTS: https://www.rfc-editor.org/rfc/rfc3986 3 | expIRes: 2030-04-12T23:20:50.52Z 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0041.stxt: -------------------------------------------------------------------------------- 1 | CONTaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | EXpIrEs: 2030-04-12T23:20:50.52Z 4 | 5 | # 6 | 7 | #󬫠") 8 | r!M: 6 | 9 | 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0085.stxt: -------------------------------------------------------------------------------- 1 | 2 | CoNTacT: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | 5 | EXpIres: 2030-04-12T23:20:50.52Z 6 | PREFErRed-LANGUaGEs: fr,fr, fr , fr 7 | 8 | 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0027.stxt: -------------------------------------------------------------------------------- 1 | conTacT: https://www.rfc-editor.org/rfc/rfc3986 2 | w.nK&: % | 3 | 6 4 | ExPIReS: 2030-04-12T23:20:50.52Z 5 | enCRYptIon: https://www.rfc-editor.org/rfc/rfc3986 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0071.stxt: -------------------------------------------------------------------------------- 1 | ENCryptiON: https://www.rfc-editor.org/rfc/rfc3986 2 | coNtact: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | 5 | # 6 | 7 | EXpirES: 2030-04-12T23:20:50.52Z 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0080.stxt: -------------------------------------------------------------------------------- 1 | # 𴆈 2 | ConTACt: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | 5 | 6 | 7 | eXpIrEs: 2030-04-12T23:20:50.52Z 8 | # 9 | PreFErred-LaNguaGes: fr 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0019.stxt: -------------------------------------------------------------------------------- 1 | cOntaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | EnCrYpTIon: https://www.rfc-editor.org/rfc/rfc3986 3 | EXPiREs: 2030-04-12T23:20:50.52Z 4 | PREFERreD-lAnGuAGes: fr , fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0022.stxt: -------------------------------------------------------------------------------- 1 | coNTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpiREs: 2030-04-12T23:20:50.52Z 3 | POLicY: https://www.rfc-editor.org/rfc/rfc3986 4 | 5 | prEfERrED-lanGUAgEs: fr 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0052.stxt: -------------------------------------------------------------------------------- 1 | enCryptIoN: https://www.rfc-editor.org/rfc/rfc3986 2 | contACt: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | expIREs: 2030-04-12T23:20:50.52Z 5 | .*`: 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0023.stxt: -------------------------------------------------------------------------------- 1 | conTacT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXPireS: 2030-04-12T23:20:50.52Z 3 | 4 | 5 | #\Aᷛ񝽗 6 | #򲐷 7 | coNtACT: https://www.rfc-editor.org/rfc/rfc3986 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0064.stxt: -------------------------------------------------------------------------------- 1 | 2 | EnCRyPtION: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | #򚺼 5 | # 6 | # 7 | conTAct: https://www.rfc-editor.org/rfc/rfc3986 8 | ExPIreS: 2030-04-12T23:20:50.52Z 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0072.stxt: -------------------------------------------------------------------------------- 1 | cONtaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | aCkNowLEDgMentS: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | 4\u: 5 | exPiRES: 2030-04-12T23:20:50.52Z 6 | 7 | 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0097.stxt: -------------------------------------------------------------------------------- 1 | CoNTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXPIREs: 2030-04-12T23:20:50.52Z 3 | 4 | prEFeRRed-languaGes: fr 5 | 6 | CONTaCt: https://www.rfc-editor.org/rfc/rfc3986 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0009.stxt: -------------------------------------------------------------------------------- 1 | cONTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | HIring: https://www.rfc-editor.org/rfc/rfc3986 3 | eXPIReS: 2030-04-12T23:20:50.52Z 4 | 5: T 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0014.stxt: -------------------------------------------------------------------------------- 1 | COnTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | # 3 | exPIrES: 2030-04-12T23:20:50.52Z 4 | pREFErrED-LanGuAgES: fr 5 | CAnONicAL: https://www.rfc-editor.org/rfc/rfc3986 6 | 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0048.stxt: -------------------------------------------------------------------------------- 1 | cOnTACT: https://www.rfc-editor.org/rfc/rfc3986 2 | poLICy: https://www.rfc-editor.org/rfc/rfc3986 3 | # 4 | eXPires: 2030-04-12T23:20:50.52Z 5 | prEfERreD-LAnGUaGES: fr , fr, fr 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0050.stxt: -------------------------------------------------------------------------------- 1 | 2 | COnTaCt: https://www.rfc-editor.org/rfc/rfc3986 3 | # s 4 | eXPIrEs: 2030-04-12T23:20:50.52Z 5 | 6 | caNONicAL: https://www.rfc-editor.org/rfc/rfc3986 7 | PRefeRred-LaNgUagES: fr 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0069.stxt: -------------------------------------------------------------------------------- 1 | EnCRYpTIon: https://www.rfc-editor.org/rfc/rfc3986 2 | cONTaCT: https://www.rfc-editor.org/rfc/rfc3986 3 | ExPiRES: 2030-04-12T23:20:50.52Z 4 | ENcRYpTIoN: https://www.rfc-editor.org/rfc/rfc3986 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0081.stxt: -------------------------------------------------------------------------------- 1 | CoNTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | COnTAct: https://www.rfc-editor.org/rfc/rfc3986 3 | policy: https://www.rfc-editor.org/rfc/rfc3986 4 | EXpiReS: 2030-04-12T23:20:50.52Z 5 | 6 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0026.stxt: -------------------------------------------------------------------------------- 1 | 2 | CONTACT: https://www.rfc-editor.org/rfc/rfc3986 3 | cONtAct: https://www.rfc-editor.org/rfc/rfc3986 4 | eXpirEs: 2030-04-12T23:20:50.52Z 5 | 6 | pRefeRReD-lAngUAges: fr, fr, fr, fr ,fr 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0040.stxt: -------------------------------------------------------------------------------- 1 | CoNTAct: https://www.rfc-editor.org/rfc/rfc3986 2 | # 3 | # 4 | ExPIreS: 2030-04-12T23:20:50.52Z 5 | 6 | pOLicY: https://www.rfc-editor.org/rfc/rfc3986 7 | # 8 | prEfeRRed-LAngUAges: fr 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0049.stxt: -------------------------------------------------------------------------------- 1 | coNtAct: https://www.rfc-editor.org/rfc/rfc3986 2 | CoNtacT: https://www.rfc-editor.org/rfc/rfc3986 3 | EXpIRes: 2030-04-12T23:20:50.52Z 4 | #𪼿 5 | PrefERRed-LanGuAGeS: fr 6 | #/ 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0090.stxt: -------------------------------------------------------------------------------- 1 | 2 | cONtAcT: https://www.rfc-editor.org/rfc/rfc3986 3 | eXpIres: 2030-04-12T23:20:50.52Z 4 | 5 | 6 | pREfeRreD-LanGuaGes: fr,fr , fr 7 | eNCRYPtIon: https://www.rfc-editor.org/rfc/rfc3986 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0096.stxt: -------------------------------------------------------------------------------- 1 | 2 | cONTaCt: https://www.rfc-editor.org/rfc/rfc3986 3 | ExPIrEs: 2030-04-12T23:20:50.52Z 4 | 5 | pREFeRrEd-lAnGuaGes: fr , fr 6 | #򆼄 7 | HIrinG: https://www.rfc-editor.org/rfc/rfc3986 8 | -------------------------------------------------------------------------------- /sectxtfuzz/src/main.rs: -------------------------------------------------------------------------------- 1 | use afl::*; 2 | use sectxtlib::SecurityTxt; 3 | 4 | fn main() { 5 | fuzz!(|data: &[u8]| { 6 | if let Ok(s) = std::str::from_utf8(data) { 7 | let _ = s.parse::(); 8 | } 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0028.stxt: -------------------------------------------------------------------------------- 1 | contACT: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | # 4 | # 5 | 6 | 7 | 8 | B-3.: 9 | ExPIreS: 2030-04-12T23:20:50.52Z 10 | PrEFeRRED-LanGuagES: fr 11 | 12 | 13 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0032.stxt: -------------------------------------------------------------------------------- 1 | acKNoWLEDGmenTs: https://www.rfc-editor.org/rfc/rfc3986 2 | COnTAct: https://www.rfc-editor.org/rfc/rfc3986 3 | ExPiReS: 2030-04-12T23:20:50.52Z 4 | pRefErRed-languages: fr,fr , fr,fr, fr , fr 5 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0021.stxt: -------------------------------------------------------------------------------- 1 | # 2 | cOnTact: https://www.rfc-editor.org/rfc/rfc3986 3 | # 4 | eXPIrES: 2030-04-12T23:20:50.52Z 5 | PreFERred-laNgUAgEs: fr,fr 6 | #󿍧 7 | enCrYpTiON: https://www.rfc-editor.org/rfc/rfc3986 8 | 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0054.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CONtacT: https://www.rfc-editor.org/rfc/rfc3986 5 | 6 | # 7 | 8 | 9 | EXpIrES: 2030-04-12T23:20:50.52Z 10 | canOnicAL: https://www.rfc-editor.org/rfc/rfc3986 11 | # 12 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0070.stxt: -------------------------------------------------------------------------------- 1 | eNCRYptiOn: https://www.rfc-editor.org/rfc/rfc3986 2 | ContaCT: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | conTACt: https://www.rfc-editor.org/rfc/rfc3986 5 | #m 6 | ExpIReS: 2030-04-12T23:20:50.52Z 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0004.stxt: -------------------------------------------------------------------------------- 1 | COntACT: https://www.rfc-editor.org/rfc/rfc3986 2 | EXPiREs: 2030-04-12T23:20:50.52Z 3 | 4 | encryPTiOn: https://www.rfc-editor.org/rfc/rfc3986 5 | policY: https://www.rfc-editor.org/rfc/rfc3986 6 | # 7 | 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0011.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | contaCt: https://www.rfc-editor.org/rfc/rfc3986 4 | # 5 | EXPIRes: 2030-04-12T23:20:50.52Z 6 | prEFerrED-LAnguAGeS: fr ,fr, fr 7 | PolicY: https://www.rfc-editor.org/rfc/rfc3986 8 | # 񹔱񫒁X 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0088.stxt: -------------------------------------------------------------------------------- 1 | coNTaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | 4 | 5 | 6 | EXpIRes: 2030-04-12T23:20:50.52Z 7 | coNtaCT: https://www.rfc-editor.org/rfc/rfc3986 8 | eNcRYPTiOn: https://www.rfc-editor.org/rfc/rfc3986 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0076.stxt: -------------------------------------------------------------------------------- 1 | #񥍃 2 | CanoniCal: https://www.rfc-editor.org/rfc/rfc3986 3 | hiRINg: https://www.rfc-editor.org/rfc/rfc3986 4 | CONtAct: https://www.rfc-editor.org/rfc/rfc3986 5 | EXpires: 2030-04-12T23:20:50.52Z 6 | PrEferred-LANgUages: fr,fr 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0010.stxt: -------------------------------------------------------------------------------- 1 | cONTaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpIREs: 2030-04-12T23:20:50.52Z 3 | #R 4 | # 5 | 6 | enCryptIOn: https://www.rfc-editor.org/rfc/rfc3986 7 | hiRinG: https://www.rfc-editor.org/rfc/rfc3986 8 | 9 | 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0039.stxt: -------------------------------------------------------------------------------- 1 | CONtAct: https://www.rfc-editor.org/rfc/rfc3986 2 | # 3 | # 4 | cOntaCt: https://www.rfc-editor.org/rfc/rfc3986 5 | ExPireS: 2030-04-12T23:20:50.52Z 6 | 7 | # T 󓙟 8 | 9 | preFerREd-laNgUagEs: fr,fr ,fr , fr 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0086.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | CoNtAcT: https://www.rfc-editor.org/rfc/rfc3986 4 | 5 | # 6 | exPires: 2030-04-12T23:20:50.52Z 7 | 8 | ENCRYPtiOn: https://www.rfc-editor.org/rfc/rfc3986 9 | PREfErrED-lANGUAGeS: fr ,fr , fr 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0059.stxt: -------------------------------------------------------------------------------- 1 | 2 | hiriNG: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | 5 | CoNTACT: https://www.rfc-editor.org/rfc/rfc3986 6 | 7 | ': 8 | F 9 | exPiReS: 2030-04-12T23:20:50.52Z 10 | PRefERreD-lANGuaGes: fr ,fr, fr 11 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0093.stxt: -------------------------------------------------------------------------------- 1 | 2 | cOntAct: https://www.rfc-editor.org/rfc/rfc3986 3 | 9V: 4 | O@ 5 | ExPIreS: 2030-04-12T23:20:50.52Z 6 | pReferReD-LAnGuAgeS: fr ,fr 7 | # 8 | aCkNoWleDgmEnTs: https://www.rfc-editor.org/rfc/rfc3986 9 | #Z# 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0094.stxt: -------------------------------------------------------------------------------- 1 | 2 | conTAcT: https://www.rfc-editor.org/rfc/rfc3986 3 | PoLicy: https://www.rfc-editor.org/rfc/rfc3986 4 | 5 | hiriNg: https://www.rfc-editor.org/rfc/rfc3986 6 | #W 7 | 8 | 9 | eXPiReS: 2030-04-12T23:20:50.52Z 10 | 11 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0042.stxt: -------------------------------------------------------------------------------- 1 | coNtacT: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | eXpIReS: 2030-04-12T23:20:50.52Z 4 | cONTACt: https://www.rfc-editor.org/rfc/rfc3986 5 | pOlicy: https://www.rfc-editor.org/rfc/rfc3986 6 | pRefErReD-lAnGuaGEs: fr , fr 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0082.stxt: -------------------------------------------------------------------------------- 1 | ACKNOWLeDGmenTs: https://www.rfc-editor.org/rfc/rfc3986 2 | CoNtact: https://www.rfc-editor.org/rfc/rfc3986 3 | expIrES: 2030-04-12T23:20:50.52Z 4 | 5 | HiRINg: https://www.rfc-editor.org/rfc/rfc3986 6 | PrEferREd-LANgUAGes: fr , fr 7 | 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0077.stxt: -------------------------------------------------------------------------------- 1 | aCknowleDgMENtS: https://www.rfc-editor.org/rfc/rfc3986 2 | COnTaCt: https://www.rfc-editor.org/rfc/rfc3986 3 | AckNowLedGMEnTS: https://www.rfc-editor.org/rfc/rfc3986 4 | # 5 | ExPIREs: 2030-04-12T23:20:50.52Z 6 | # 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0003.stxt: -------------------------------------------------------------------------------- 1 | ContacT: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | eXPIRes: 2030-04-12T23:20:50.52Z 4 | 5 | HIriNG: https://www.rfc-editor.org/rfc/rfc3986 6 | hIriNg: https://www.rfc-editor.org/rfc/rfc3986 7 | CanoNicAL: https://www.rfc-editor.org/rfc/rfc3986 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0065.stxt: -------------------------------------------------------------------------------- 1 | COnTaCt: https://www.rfc-editor.org/rfc/rfc3986 2 | EncRYPtiON: https://www.rfc-editor.org/rfc/rfc3986 3 | contACT: https://www.rfc-editor.org/rfc/rfc3986 4 | exPiReS: 2030-04-12T23:20:50.52Z 5 | 6 | CANonicaL: https://www.rfc-editor.org/rfc/rfc3986 7 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0098.stxt: -------------------------------------------------------------------------------- 1 | # 2 | CoNTacT: https://www.rfc-editor.org/rfc/rfc3986 3 | 4 | CaNonIcal: https://www.rfc-editor.org/rfc/rfc3986 5 | eXPireS: 2030-04-12T23:20:50.52Z 6 | pREfeRRed-laNGuaGes: fr 7 | 8 | CaNONIcaL: https://www.rfc-editor.org/rfc/rfc3986 9 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0038.stxt: -------------------------------------------------------------------------------- 1 | cOnTact: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | 4 | 5 | aCKNOWlEdgmenTS: https://www.rfc-editor.org/rfc/rfc3986 6 | expirES: 2030-04-12T23:20:50.52Z 7 | 8 | pREFErrED-lAnGuAgeS: fr 9 | eNcRyPTION: https://www.rfc-editor.org/rfc/rfc3986 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0073.stxt: -------------------------------------------------------------------------------- 1 | cONtACt: https://www.rfc-editor.org/rfc/rfc3986 2 | expIRes: 2030-04-12T23:20:50.52Z 3 | HirINg: https://www.rfc-editor.org/rfc/rfc3986 4 | caNOniCal: https://www.rfc-editor.org/rfc/rfc3986 5 | 6 | cONTacT: https://www.rfc-editor.org/rfc/rfc3986 7 | 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0083.stxt: -------------------------------------------------------------------------------- 1 | poLIcy: https://www.rfc-editor.org/rfc/rfc3986 2 | 3 | coNtAcT: https://www.rfc-editor.org/rfc/rfc3986 4 | ExpireS: 2030-04-12T23:20:50.52Z 5 | 6 | CAnONICaL: https://www.rfc-editor.org/rfc/rfc3986 7 | 8 | 9 | preFeRrED-LANguAGeS: fr ,fr 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | max_line_length = 120 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0031.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | contAct: https://www.rfc-editor.org/rfc/rfc3986 4 | ExPireS: 2030-04-12T23:20:50.52Z 5 | eNCrYPtiOn: https://www.rfc-editor.org/rfc/rfc3986 6 | 7 | # 8 | ackNoWLeDgMenTS: https://www.rfc-editor.org/rfc/rfc3986 9 | pREFErrED-lAnGUageS: fr 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0053.stxt: -------------------------------------------------------------------------------- 1 | COntAct: https://www.rfc-editor.org/rfc/rfc3986 2 | ExpIREs: 2030-04-12T23:20:50.52Z 3 | pReferrED-lANgUageS: fr , fr 4 | #H V 5 | # 6 | 7 | eNCrYPtION: https://www.rfc-editor.org/rfc/rfc3986 8 | ACknowLEdgMents: https://www.rfc-editor.org/rfc/rfc3986 9 | 10 | 11 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0058.stxt: -------------------------------------------------------------------------------- 1 | #c U 2 | # 3 | coNTact: https://www.rfc-editor.org/rfc/rfc3986 4 | cAnonicaL: https://www.rfc-editor.org/rfc/rfc3986 5 | 6 | expirEs: 2030-04-12T23:20:50.52Z 7 | prEfERRed-LaNguAges: fr,fr ,fr,fr 8 | 9 | COntAct: https://www.rfc-editor.org/rfc/rfc3986 10 | 11 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/valid_unsigned/github_com.stxt: -------------------------------------------------------------------------------- 1 | Contact: https://hackerone.com/github 2 | Acknowledgments: https://hackerone.com/github/hacktivity 3 | Preferred-Languages: en 4 | Canonical: https://github.com/.well-known/security.txt 5 | Policy: https://bounty.github.com 6 | Hiring: https://github.com/about/careers 7 | Expires: 2023-04-10T22:38:09z 8 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0057.stxt: -------------------------------------------------------------------------------- 1 | COnTaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | eXpireS: 2030-04-12T23:20:50.52Z 3 | 4 | 5 | AcKNoWLEDgmenTS: https://www.rfc-editor.org/rfc/rfc3986 6 | # 7 | ENCrYptIon: https://www.rfc-editor.org/rfc/rfc3986 8 | AcKNoWLedGMenTs: https://www.rfc-editor.org/rfc/rfc3986 9 | 10 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0016.stxt: -------------------------------------------------------------------------------- 1 | 2 | cOnTAct: https://www.rfc-editor.org/rfc/rfc3986 3 | PoLicY: https://www.rfc-editor.org/rfc/rfc3986 4 | eXPIrES: 2030-04-12T23:20:50.52Z 5 | 6 | ConTACt: https://www.rfc-editor.org/rfc/rfc3986 7 | PrefERRED-lAnGuAges: fr,fr 8 | 9 | PoliCY: https://www.rfc-editor.org/rfc/rfc3986 10 | 11 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0030.stxt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoNTaCT: https://www.rfc-editor.org/rfc/rfc3986 6 | 7 | eXpIRes: 2030-04-12T23:20:50.52Z 8 | 9 | 10 | CONtaCT: https://www.rfc-editor.org/rfc/rfc3986 11 | ConTACT: https://www.rfc-editor.org/rfc/rfc3986 12 | caNONical: https://www.rfc-editor.org/rfc/rfc3986 13 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0020.stxt: -------------------------------------------------------------------------------- 1 | CONTACt: https://www.rfc-editor.org/rfc/rfc3986 2 | (-4q: 3 | 4 | EXPIrEs: 2030-04-12T23:20:50.52Z 5 | 6 | 7 | 6m'5n: 8 | ACKNOwLEDGmENts: https://www.rfc-editor.org/rfc/rfc3986 9 | 10 | pOliCY: https://www.rfc-editor.org/rfc/rfc3986 11 | PREFeRRED-lAnguagEs: fr, fr 12 | 13 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0007.stxt: -------------------------------------------------------------------------------- 1 | # 2 | #񪿢7 3 | enCrypTIoN: https://www.rfc-editor.org/rfc/rfc3986 4 | COnTAct: https://www.rfc-editor.org/rfc/rfc3986 5 | 6 | # 7 | #| 8 | #򤯂 9 | eXPIREs: 2030-04-12T23:20:50.52Z 10 | cONtAcT: https://www.rfc-editor.org/rfc/rfc3986 11 | !9: FVF f? 12 | # 13 | > 14 | ^ O>.|Qd 15 | # 16 | 17 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0074.stxt: -------------------------------------------------------------------------------- 1 | POLicY: https://www.rfc-editor.org/rfc/rfc3986 2 | CoNTact: https://www.rfc-editor.org/rfc/rfc3986 3 | caNOnIcal: https://www.rfc-editor.org/rfc/rfc3986 4 | 5 | exPiREs: 2030-04-12T23:20:50.52Z 6 | AcKnowLEDGmENts: https://www.rfc-editor.org/rfc/rfc3986 7 | 8 | 9 | pREFerREd-lAnGuagEs: fr 10 | 11 | 12 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/gen_unsigned/gen_unsigned_0075.stxt: -------------------------------------------------------------------------------- 1 | CoNTaCT: https://www.rfc-editor.org/rfc/rfc3986 2 | EXPIREs: 2030-04-12T23:20:50.52Z 3 | Hiring: https://www.rfc-editor.org/rfc/rfc3986 4 | # 5 | 6 | CaNONicAl: https://www.rfc-editor.org/rfc/rfc3986 7 | HIRInG: https://www.rfc-editor.org/rfc/rfc3986 8 | "$tmp_directory/top.txt" 26 | 27 | ./target/release/sectxt --threads 50 --timeout 5 --quiet < "$tmp_directory/top.txt" 28 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/valid_signed/securitytxt_org.stxt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA512 3 | 4 | Contact: https://hackerone.com/ed 5 | Expires: 2024-03-14T00:00:00.000Z 6 | Acknowledgments: https://hackerone.com/ed/thanks 7 | Preferred-Languages: en, fr, de 8 | Canonical: https://securitytxt.org/.well-known/security.txt 9 | Policy: https://hackerone.com/ed?type=team&view_policy=true 10 | -----BEGIN PGP SIGNATURE----- 11 | 12 | iHUEARYKAB0WIQSsP2kEdoKDVFpSg6u3rK+YCkjapwUCY9qRaQAKCRC3rK+YCkja 13 | pwALAP9LEHSYMDW4h8QRHg4MwCzUdnbjBLIvpq4QTo3dIqCUPwEA31MsEf95OKCh 14 | MTHYHajOzjwpwlQVrjkK419igx4imgk= 15 | =KONn 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "cargo", 6 | "subcommand": "build", 7 | "presentation": { 8 | "panel": "shared", 9 | "reveal": "always", 10 | "focus": true 11 | }, 12 | "problemMatcher": [ 13 | "$rustc" 14 | ], 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | } 19 | }, 20 | { 21 | "label": "test", 22 | "type": "shell", 23 | "command": "make test", 24 | "presentation": { 25 | "panel": "shared", 26 | "reveal": "always", 27 | "focus": true 28 | }, 29 | "problemMatcher": [], 30 | "group": { 31 | "kind": "test", 32 | "isDefault": true 33 | } 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /scripts/checkalexa1m: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o errtrace 5 | 6 | SOURCEURL='http://s3.amazonaws.com/alexa-static/top-1m.csv.zip' 7 | 8 | cargo build --release -p sectxt 9 | 10 | tmp_directory="$(mktemp -d)" 11 | 12 | exit_handler() { 13 | rm -r "$tmp_directory" 14 | } 15 | 16 | trap exit_handler EXIT 17 | 18 | curl \ 19 | --disable \ 20 | --location \ 21 | --max-time 60 \ 22 | --output "$tmp_directory/top.csv.zip" \ 23 | "$SOURCEURL" 24 | 25 | unzip "$tmp_directory/top.csv.zip" -d "$tmp_directory" 26 | 27 | xsv select 2 "$tmp_directory/top-1m.csv" | sort -u > "$tmp_directory/top.txt" 28 | 29 | ./target/release/sectxt --threads 50 --timeout 5 --quiet < "$tmp_directory/top.txt" 30 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/valid_unsigned/wordpress_org.stxt: -------------------------------------------------------------------------------- 1 | Contact: https://hackerone.com/wordpress 2 | Expires: 2024-12-31T15:00:00.000Z 3 | Acknowledgments: https://hackerone.com/wordpress/thanks 4 | Canonical: https://wordpress.org/.well-known/security.txt 5 | Policy: https://make.wordpress.org/core/handbook/testing/reporting-security-vulnerabilities/ 6 | 7 | # The above contact is for reporting security issues in core WordPress software itself. 8 | # For reporting issues in a plugin hosted at wordpress.org, contact plugins@wordpress.org 9 | # If your website is hacked, please contact your site administrator or hosting provider. 10 | # Additionally, community support forums are a good resource at https://wordpress.org/support/ 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License (ISC) 2 | 3 | Copyright 2020-2023 eikendev 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 8 | -------------------------------------------------------------------------------- /sectxtbin/src/settings.rs: -------------------------------------------------------------------------------- 1 | use argh::FromArgs; 2 | 3 | #[derive(FromArgs)] 4 | /// A tool for working with security.txt files. 5 | pub struct Settings { 6 | /// number of simultaneous domains to process 7 | #[argh(option, default = "30")] 8 | pub threads: usize, 9 | 10 | /// seconds to wait before giving up a domain 11 | #[argh(option, default = "3")] 12 | pub timeout: u64, 13 | 14 | /// whether to be strict with line endings or more relaxed 15 | #[argh(switch)] 16 | pub strict: bool, 17 | 18 | /// only print domains for which the run was successful 19 | #[argh(switch, short = 'q')] 20 | pub quiet: bool, 21 | 22 | /// print statistics before exit 23 | #[argh(switch)] 24 | pub print_stats: bool, 25 | } 26 | -------------------------------------------------------------------------------- /sectxtlib/src/securitytxt_options.rs: -------------------------------------------------------------------------------- 1 | use chrono::{DateTime, Utc}; 2 | 3 | /// Options for parsing a security.txt file 4 | #[derive(Clone, Debug)] 5 | pub struct SecurityTxtOptions { 6 | /// The current date and time to validate the "Expires" field against 7 | pub now: DateTime, 8 | 9 | /// Whether to be strict with line endings or more relaxed 10 | pub strict: bool, 11 | } 12 | 13 | impl SecurityTxtOptions { 14 | pub fn new(strict: bool) -> Self { 15 | Self { 16 | now: Utc::now(), 17 | strict, 18 | } 19 | } 20 | } 21 | 22 | impl Default for SecurityTxtOptions { 23 | fn default() -> Self { 24 | Self { 25 | now: Utc::now(), 26 | strict: true, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sectxtbin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sectxt" 3 | version = "0.4.0" 4 | authors = ["eikendev"] 5 | edition = "2021" 6 | description = "A tool for working with security.txt files as specified in RFC 9116" 7 | homepage = "https://github.com/eikendev/sectxt" 8 | repository = "https://github.com/eikendev/sectxt.git" 9 | readme = "README.md" 10 | license = "ISC" 11 | 12 | [dependencies] 13 | sectxtlib = { path = "../sectxtlib", version = "0.4.0" } 14 | anyhow = "1.0.98" 15 | argh = "0.1.13" 16 | futures = "0.3.31" 17 | human-panic = "2.0.3" 18 | lazy_static = "1.5.0" 19 | reqwest = "0.12.22" 20 | tracing = "0.1.41" 21 | tracing-subscriber = { version = ">=0.3.20", features = ["env-filter", "json", "valuable"] } 22 | url = "2.5.4" 23 | valuable = "0.1.1" 24 | 25 | [dependencies.tokio] 26 | version = "1.47.0" 27 | features = ["rt-multi-thread", "macros"] 28 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/valid_signed/rfc_signed.stxt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA256 3 | 4 | # Canonical URI 5 | Canonical: https://example.com/.well-known/security.txt 6 | 7 | # Our security address 8 | Contact: mailto:security@example.com 9 | 10 | # Our OpenPGP key 11 | Encryption: https://example.com/pgp-key.txt 12 | 13 | # Our security policy 14 | Policy: https://example.com/security-policy.html 15 | 16 | # Our security acknowledgments page 17 | Acknowledgments: https://example.com/hall-of-fame.html 18 | 19 | Expires: 2023-12-31T18:37:07z 20 | -----BEGIN PGP SIGNATURE----- 21 | Version: GnuPG v2.2 22 | 23 | iHUEARYKAB0WIQSsP2kEdoKDVFpSg6u3rK+YCkjapwUCY9qRaQAKCRC3rK+YCkja 24 | pwALAP9LEHSYMDW4h8QRHg4MwCzUdnbjBLIvpq4QTo3dIqCUPwEA31MsEf95OKCh 25 | MTHYHajOzjwpwlQVrjkK419igx4imgk= 26 | =KONn 27 | -----END PGP SIGNATURE----- 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET_DIR := ./target 2 | FUZZ_DIR := ./fuzz 3 | 4 | .PHONY: build 5 | build: build_bin docs 6 | 7 | .PHONY: build_bin 8 | build_bin: 9 | cargo build -p sectxtlib 10 | cargo build -p sectxt 11 | 12 | .PHONY: docs 13 | docs: 14 | cargo doc -p sectxtlib 15 | 16 | .PHONY: test 17 | test: 18 | cargo fmt -p sectxtlib --check 19 | cargo fmt -p sectxt --check 20 | cargo clippy -p sectxtlib --all-features -- -D warnings 21 | cargo clippy -p sectxt --all-features -- -D warnings 22 | cargo test 23 | 24 | .PHONY: setup 25 | setup: 26 | rustup update 27 | rustup component add clippy 28 | rustup component add rustfmt 29 | rustup show 30 | cargo install cargo-afl 31 | 32 | .PHONY: publish 33 | publish: 34 | cargo publish -p sectxtlib 35 | cargo publish -p sectxt 36 | 37 | .PHONY: fuzz 38 | fuzz: 39 | cargo afl build -p sectxtfuzz 40 | AFL_SKIP_CPUFREQ=1 cargo afl fuzz -i $(FUZZ_DIR)/_examples -o $(FUZZ_DIR)/afl $(TARGET_DIR)/debug/sectxtfuzz 41 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: push 4 | 5 | jobs: 6 | test_publish: 7 | name: Test and publish 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v3 12 | 13 | - name: Install dependencies 14 | run: make setup 15 | 16 | - name: Run tests 17 | run: make test 18 | 19 | - name: Build 20 | run: make build 21 | 22 | - name: Publish (dry run) 23 | if: ${{ !startsWith(github.ref, 'refs/tags/v') }} # Only dry-run if not a release. 24 | run: | 25 | cargo publish --dry-run -p sectxtlib 26 | #cargo publish --dry-run -p sectxt # Fails if sectxtlib is not actually published 27 | 28 | - name: Publish 29 | if: startsWith(github.ref, 'refs/tags/v') # Only publish for new release. 30 | env: 31 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 32 | run: make publish 33 | -------------------------------------------------------------------------------- /sectxtbin/src/network.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Context, Result}; 2 | use reqwest::Response; 3 | use sectxtlib::{SecurityTxt, SecurityTxtOptions}; 4 | 5 | pub fn is_file_present(result: Result) -> Result { 6 | let resp = result.context("HTTP request failed")?; 7 | 8 | if resp.status() != reqwest::StatusCode::OK { 9 | anyhow::bail!("HTTP status code not OK"); 10 | } 11 | 12 | Ok(resp) 13 | } 14 | 15 | pub async fn is_securitytxt(resp: Response, options: &SecurityTxtOptions) -> Result { 16 | if let Some(content_type) = resp.headers().get("Content-Type") { 17 | let value: &str = content_type.to_str().context("error parsing HTTP body")?; 18 | 19 | if value.starts_with("text/plain") && value.contains("charset=utf-8") { 20 | let s = resp.text().await.context("error parsing HTTP body")?; 21 | Ok(SecurityTxt::parse_with(&s, options)?) 22 | } else { 23 | anyhow::bail!("invalid HTTP content type"); 24 | } 25 | } else { 26 | anyhow::bail!("HTTP content type not specified"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sectxtlib/README.md: -------------------------------------------------------------------------------- 1 |
2 |

sectxtlib

3 |

4 | The security.txt standard helps us make the Internet more secure. 5 |

6 |

sectxtlib parses and validates security.txt files as specified in RFC 9116.

7 |
8 | 9 |

10 | Build status  11 | License  12 | Docs  13 | Version  14 | Downloads  15 |

16 | 17 | ## 📄 Usage 18 | 19 | Best have a look at [the documentation](https://docs.rs/sectxtlib/latest/sectxtlib/) for examples. 20 | -------------------------------------------------------------------------------- /sectxtlib/src/parse_error.rs: -------------------------------------------------------------------------------- 1 | use iri_string::validate; 2 | use oxilangtag::LanguageTagParseError; 3 | use thiserror::Error; 4 | 5 | #[derive(Error, Debug, PartialEq)] 6 | pub enum ParseError { 7 | #[error("invalid syntax")] 8 | Malformed, 9 | #[error("invalid date format")] 10 | InvalidDatetime(#[from] chrono::format::ParseError), 11 | #[error("field specified in an illegal way")] 12 | IllegalField, 13 | #[error("contact field must be specified")] 14 | ContactFieldMissing, 15 | #[error("expires field must be specified")] 16 | ExpiresFieldMissing, 17 | #[error("expires field specifies time in the past")] 18 | ExpiresFieldExpired, 19 | #[error("expires field may only be specified once")] 20 | ExpiresFieldMultiple, 21 | #[error("preferred languages field may only be specified once")] 22 | PreferredLanguagesFieldMultiple, 23 | #[error("links must use HTTPS")] 24 | InsecureHTTP, 25 | } 26 | 27 | macro_rules! impl_from { 28 | ( $for:path, $from:path, $to:path ) => { 29 | impl From<$from> for $for { 30 | fn from(_: $from) -> $for { 31 | $to 32 | } 33 | } 34 | }; 35 | } 36 | 37 | impl_from!(ParseError, validate::Error, ParseError::Malformed); 38 | impl_from!(ParseError, nom::Err>, ParseError::Malformed); 39 | impl_from!(ParseError, LanguageTagParseError, ParseError::Malformed); 40 | -------------------------------------------------------------------------------- /sectxtbin/README.md: -------------------------------------------------------------------------------- 1 |
2 |

sectxt

3 |

4 | The security.txt standard helps us make the Internet more secure. 5 |

6 |

sectxt lets you work with security.txt files on the command line.

7 |
8 | 9 |

10 | Build status  11 | License  12 | Version  13 | Downloads  14 |

15 | 16 | ## 🚀 Installation 17 | 18 | ```bash 19 | RUSTFLAGS="--cfg tracing_unstable" cargo install sectxt 20 | ``` 21 | 22 | Please refer to [issue #15](https://github.com/eikendev/sectxt/issues/15) for details. 23 | 24 | ## 📄 Usage 25 | 26 | Feed `sectxt` a list of domains and it tells you which of them implement [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116) correctly. 27 | ```bash 28 | sectxt < domains.txt 29 | ``` 30 | 31 | ## 👮 Acknowledgments 32 | 33 | The idea was ~~shamelessly stolen from~~ inspired by [haksecuritytxt](https://github.com/hakluke/haksecuritytxt). 34 | The main motivation was to play around with [Rust](https://www.rust-lang.org/)'s new `async`/`await` syntax and learn something new. 35 | Besides, `sectxt` enforces stricter checks against the [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116). 36 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/valid_signed/redhat.stxt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA256 3 | 4 | # Report any suspected security vulnerability in Red Hat software to Red Hat Product Security at: 5 | Contact: https://access.redhat.com/security/team/contact/ 6 | Contact: mailto:secalert@redhat.com 7 | # Report an issue in any Red Hat branded website or online service to Red Hat Information Security 8 | # by following the instructions at: 9 | # https://www.redhat.com/en/trust/RFC-2350 10 | 11 | Preferred-Languages: en 12 | 13 | # Red Hat Product Security OpenPGP key fingerprint: 14 | # 77E7 9ABE 9367 3533 ED09 EBE2 DCE3 8235 97F5 EAC4 15 | Encryption: https://access.redhat.com/security/data/97f5eac4.txt 16 | 17 | # Vulnerability acknowledgments for Red Hat online services: 18 | Acknowledgments: https://access.redhat.com/articles/66234 19 | # Vulnerability acknowledgments for Red Hat offerings are listed on individual CVE pages at: 20 | # https://access.redhat.com/security/security-updates/#/cve 21 | 22 | CSAF: https://www.redhat.com/.well-known/csaf/provider-metadata.json 23 | 24 | # https://www.cve.org/PartnerInformation/ListofPartners/partner/redhat 25 | CNA: mailto:secalert@redhat.com 26 | CNA: mailto:RootCNA-Coordination@redhat.com 27 | 28 | Expires: 2025-03-15T00:00:00.000Z 29 | -----BEGIN PGP SIGNATURE----- 30 | Version: GnuPG v1 31 | 32 | iQIcBAEBCAAGBQJmC9AYAAoJENzjgjWX9erEAbcQAKHhwzlY+ZGre5Z+2CJkDlU8 33 | oYep+JN2C6T1heo6f79thsxXfu5SInLW3QQjiswAS7IzWzpoha/L41HzV2BoyraQ 34 | D++R+4wi7bMhNqhAotDQ58KoKqNPPsY3FM9pthcoGyZNvsODxlzbMwGgUKciyBde 35 | NPIa2z48auHI9raGyWFfT3EA5Vh6sCn2GrquCx+2EPndUR/4rsYak0kCWhXDKsoK 36 | xtpx5Dk7xTFUr7gl1g2wDUb/mx5xkT8OGHagbD1zfKfwdDukNV/8biy5gPdn+xzY 37 | oq1j7j/fcqJko6ALsMf7WzoPJfvC/xLn9czEh3EESLGcTUvA9UTt1Lutk4cMdOd7 38 | +VjdnyGqm7thBd1WqJ2Zx4+7JgQ+qqa1pgo70w63lfzkZCz5Tpin2Gy/+jZSIqPA 39 | 2SM0fw3jHbrAa8WHum+aYrgZVDl8JGLpYC6vZfVzysO6jJXT6zdFB/iYYVPDJn9G 40 | Z1zogkrlqLAkTCruoTMeUZkLd6BmMQ8mOy7rB+Fy0W1c55c4i7uR+SpIdLl5ylZl 41 | 8t9z0rHbq8oDaoxliN30Xi+kCio7vmwqx+fpJDATY8a8kGqcOpRBaFGGAeLWwcxZ 42 | XvHAhiINI9VINAddGRedtQXEXBAkuzPxL31ej7Xjp+HUaAVtxA53p62/CfqSSJp1 43 | FnQbWMEamIs/PDNIpTEv 44 | =K59c 45 | -----END PGP SIGNATURE----- 46 | -------------------------------------------------------------------------------- /sectxtbin/src/website.rs: -------------------------------------------------------------------------------- 1 | use super::network::{is_file_present, is_securitytxt}; 2 | use super::status::Status; 3 | use anyhow::{Context, Result}; 4 | use sectxtlib::SecurityTxtOptions; 5 | use std::convert::TryFrom; 6 | use tracing::info; 7 | use url::Url; 8 | use valuable::Valuable; 9 | 10 | pub struct Website { 11 | pub domain: String, 12 | pub urls: Vec, 13 | } 14 | 15 | impl Website { 16 | fn make_status(&self, available: bool) -> Status { 17 | Status { 18 | domain: self.domain.to_owned(), 19 | available, 20 | } 21 | } 22 | 23 | pub async fn get_status(&self, client: &reqwest::Client, options: &SecurityTxtOptions, quiet: bool) -> Status { 24 | let mut first_error: Option = None; 25 | 26 | for url in &self.urls { 27 | let response = client.get(&url[..]).send().await; 28 | 29 | match is_file_present(response) { 30 | Ok(response) => match is_securitytxt(response, options).await { 31 | Ok(txt) => { 32 | // Location exists and file is parsable. 33 | info!(domain = self.domain, content = txt.as_value(), status = "OK"); 34 | return self.make_status(true); 35 | } 36 | Err(err) => { 37 | // Location exists but file is not parsable. 38 | if !quiet { 39 | info!(domain = self.domain, error = err.to_string(), status = "ERR"); 40 | } 41 | return self.make_status(false); 42 | } 43 | }, 44 | Err(err) => { 45 | // Location does not exists. 46 | if first_error.is_none() { 47 | first_error = Some(err); 48 | } 49 | } 50 | } 51 | } 52 | 53 | if !quiet { 54 | let err = first_error.unwrap(); // self.urls is never empty 55 | info!(domain = self.domain, error = err.to_string(), status = "ERR"); 56 | } 57 | 58 | self.make_status(false) 59 | } 60 | } 61 | 62 | impl TryFrom<&str> for Website { 63 | type Error = anyhow::Error; 64 | 65 | fn try_from(s: &str) -> Result { 66 | let url = Url::parse(s).context("unable to parse input as URL")?; 67 | let host = url.host_str().context("cannot parse hostname in input")?; 68 | 69 | Ok(Website { 70 | domain: host.to_owned(), 71 | urls: vec![ 72 | format!("https://{host}/.well-known/security.txt"), 73 | format!("https://{host}/security.txt"), 74 | ], 75 | }) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /sectxtlib/resources/test/valid_signed/opera_com.stxt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA256 3 | 4 | # Please always try to contact Opera Security Team through our responsible disclosure form which is available 5 | # under Report an Issue to speed up things. Keep in mind that there are also separate dedicated forms for 6 | # reporting a fraud page or submitting privacy inquiry. 7 | Contact: https://security.opera.com 8 | # Reporting an issue regarding Opera assets covered by Opera Public Bug Bounty should be done at: 9 | Contact: https://bugcrowd.com/opera 10 | # Should that not be an option please reach to us via following email address: 11 | Contact: mailto:security@opera.com 12 | 13 | # You shouldn't trust this file, once it has expired. 14 | # We are sometimes a bit forgetful, but we do have an annual re-occuring task to keep this file up-to-date. 15 | Expires: 2024-04-01T00:00:00.000Z 16 | 17 | # Opera Security Team PGP key: 18 | # pub rsa4096/0x4A1BB804224DE5A4 2017-11-09 [SC] [expires: 2027-11-08] 19 | # Key fingerprint = 62CD 131B B064 9427 08AC FE62 4A1B B804 224D E5A4 20 | # uid Opera Security Team 21 | # Available at: 22 | Encryption: https://security.opera.com/gpg-key/ 23 | # Or via PGP keyservers: hkps://keyserver.ubuntu.com and hkps://pgp.mit.edu 24 | # Example: gpg --keyserver hkps://pgp.mit.edu --recv-keys 62cd131bb064942708acfe624a1bb804224de5a4 25 | Encryption: openpgp4fpr:62cd131bb064942708acfe624a1bb804224de5a4 26 | 27 | # Hall of Fame honouring resarchers that helped Opera improve security can be found at: 28 | Acknowledgments: https://security.opera.com/hall-of-fame/ 29 | # Up to date Opera Public Bug Bounty hall of fame can be found at: 30 | Acknowledgments: https://bugcrowd.com/opera/hall-of-fame 31 | 32 | # We can offer you a proper response in the following languages: 33 | Preferred-Languages: en, pl 34 | 35 | # If you would like to report a security issue please first read our responsible disclosure policy: 36 | Policy: https://security.opera.com/policy/ 37 | 38 | # Opera is hiring and looking for people like you! Current opening can be found at: 39 | Hiring: https://jobs.opera.com 40 | Hiring: https://linkedin.com/company/opera-software/jobs 41 | -----BEGIN PGP SIGNATURE----- 42 | 43 | iQIzBAEBCAAdFiEEYs0TG7BklCcIrP5iShu4BCJN5aQFAmQiw0QACgkQShu4BCJN 44 | 5aTXEg//RVPbpuXYp7tYLAhhlwqucq1+30DwLODRpXgxKrRUONbTbt4P6Mznsnrz 45 | W1GB0lM3oMaN85gq0PG1hwRIx6k5GoF1XpROg1D3F+B8H53XVPdqHX3HT/82C73o 46 | Q7zDahlmD183CifPIGtA1RIba/Z1SGel6o4m3JZjBRCeDDHJgV5E4mM5AtFtMWvC 47 | jCIPaZ9rmlWT/TY95y6Sq3J9KsnWzoRPbm724Sz6HeMa2z7KzU/9CWkixm1DIK8A 48 | yQyqGxB8JkLqQRumkoarQ/H2qoB03Pr4zIo8wLaErMxsU6kNqenH1WPZCsYjLKqD 49 | dwubk+fnPRPMAUEEpvFgpHgY8sBDQsXeffZBBw+7qMXj/tnznLezoPqFwLb3dgB8 50 | /Vk/pfEH1TKZhUIvu83wb8p4o3UG51ErRvhCTvL+Mn2FDb6bYKqMuO1uIXEcwkjn 51 | ZgbzAl7r3iIRByYcL2sC1cNJGUuzH6Y48u4EL0tl85KN0XChaq5hAZ5+GQBdrEE3 52 | kgHY90Vi5qcLVx9lw/5t6UElnzz9AagALAP66mgKOAb00ZfOuXSRS5lKcTCnghN0 53 | YpxoFO1LG9O2QaE2XhHo26VBARlXbVf1dEB2oSBzYHB7Fti9qpUn82zeidXYqhPJ 54 | hFT/zl5/X4kM7sQsJUncGXjO4w3CzsUwEgv7bnvWja4x6KANDso= 55 | =BfcH 56 | -----END PGP SIGNATURE----- 57 | -------------------------------------------------------------------------------- /sectxtbin/src/main.rs: -------------------------------------------------------------------------------- 1 | mod network; 2 | mod settings; 3 | mod status; 4 | mod website; 5 | 6 | use futures::channel::mpsc::channel; 7 | use futures::{Stream, StreamExt}; 8 | use lazy_static::*; 9 | use reqwest::Client; 10 | use sectxtlib::SecurityTxtOptions; 11 | use settings::Settings; 12 | use status::Status; 13 | use std::io::BufRead; 14 | use std::time::Duration; 15 | use tracing::{debug, info}; 16 | use tracing_subscriber::prelude::*; 17 | use tracing_subscriber::{fmt, EnvFilter}; 18 | use website::Website; 19 | 20 | fn stdin(threads: usize) -> impl Stream { 21 | let (mut tx, rx) = channel(threads); 22 | 23 | std::thread::spawn(move || { 24 | for line in std::io::stdin().lock().lines().map_while(Result::ok) { 25 | loop { 26 | let status = tx.try_send(line.to_owned()); 27 | 28 | match status { 29 | Err(e) if e.is_full() => continue, 30 | _ => break, 31 | } 32 | } 33 | } 34 | }); 35 | 36 | rx 37 | } 38 | 39 | async fn process_line(line: String, client: &Client, options: &SecurityTxtOptions, quiet: bool) -> Status { 40 | let mut line = line.trim().to_lowercase(); 41 | if !line.starts_with("http") { 42 | line = format!("https://{line}"); 43 | } 44 | let website = Website::try_from(&line[..]); 45 | 46 | match website { 47 | Ok(website) => website.get_status(client, options, quiet).await, 48 | Err(e) => { 49 | if !quiet { 50 | info!(domain = &line, error = e.to_string(), status = "ERR"); 51 | } 52 | 53 | Status { 54 | domain: line, 55 | available: false, 56 | } 57 | } 58 | } 59 | } 60 | 61 | #[tokio::main] 62 | async fn process_domains(s: &'static Settings) -> (u64, u64) { 63 | let client = reqwest::Client::builder() 64 | .timeout(Duration::from_secs(s.timeout)) 65 | .build() 66 | .unwrap(); 67 | 68 | let options: SecurityTxtOptions = SecurityTxtOptions::new(s.strict); 69 | 70 | let statuses = stdin(s.threads) 71 | .map(|input| { 72 | let client = &client; 73 | let options = &options; 74 | async move { process_line(input, client, options, s.quiet).await } 75 | }) 76 | .buffer_unordered(s.threads); 77 | 78 | let count: (u64, u64) = statuses 79 | .fold((0, 0), |acc, status: Status| async move { 80 | debug!(domain = &status.domain, available = status.available); 81 | match s { 82 | _ if status.available => (acc.0 + 1, acc.1 + 1), 83 | _ => (acc.0 + 1, acc.1), 84 | } 85 | }) 86 | .await; 87 | 88 | count 89 | } 90 | 91 | fn setup_logger() { 92 | let format_layer = fmt::layer() 93 | .with_level(true) 94 | .with_target(false) 95 | .with_thread_ids(false) 96 | .with_thread_names(false) 97 | .without_time() 98 | .json(); 99 | 100 | let filter_layer = EnvFilter::try_from_default_env() 101 | .or_else(|_| EnvFilter::try_new("info")) 102 | .unwrap(); 103 | 104 | tracing_subscriber::registry() 105 | .with(filter_layer) 106 | .with(format_layer) 107 | .init(); 108 | } 109 | 110 | fn main() { 111 | human_panic::setup_panic!(); 112 | 113 | lazy_static! { 114 | static ref SETTINGS: Settings = argh::from_env(); 115 | } 116 | 117 | setup_logger(); 118 | 119 | let count = process_domains(&SETTINGS); 120 | 121 | if SETTINGS.print_stats { 122 | println!("{}/{}", count.0, count.1); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /sectxtlib/src/securitytxt.rs: -------------------------------------------------------------------------------- 1 | use crate::parsers::SecurityTxtParser; 2 | use crate::pgpcleartextmessage::PGPCleartextMessageParser; 3 | 4 | use super::fields::{ 5 | AcknowledgmentsField, CanonicalField, ContactField, CsafField, EncryptionField, ExpiresField, ExtensionField, 6 | HiringField, PolicyField, PreferredLanguagesField, 7 | }; 8 | use super::parse_error::ParseError; 9 | use super::raw_field::RawField; 10 | use super::securitytxt_options::SecurityTxtOptions; 11 | use std::cmp::Ordering; 12 | use std::str::FromStr; 13 | use valuable::Valuable; 14 | 15 | /// A representation of an [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116) security.txt file 16 | #[derive(Debug, PartialEq, Valuable)] 17 | pub struct SecurityTxt { 18 | /// A collection of "Acknowledgments" fields 19 | pub acknowledgments: Vec, 20 | 21 | /// A collection of "Canonical" fields 22 | pub canonical: Vec, 23 | 24 | /// A collection of "Contact" fields 25 | pub contact: Vec, 26 | 27 | /// A collection of "CSAF" fields, 28 | pub csaf: Vec, 29 | 30 | /// A collection of "Encryption" fields 31 | pub encryption: Vec, 32 | 33 | /// The "Expires" field 34 | pub expires: ExpiresField, 35 | 36 | /// A collection of "Extension" fields 37 | pub extension: Vec, 38 | 39 | /// A collection of "Hiring" fields 40 | pub hiring: Vec, 41 | 42 | /// A collection of "Policy" fields 43 | pub policy: Vec, 44 | 45 | /// The "Preferred-Languages" field, if available 46 | pub preferred_languages: Option, 47 | } 48 | 49 | impl SecurityTxt { 50 | fn validate_contact_fields(fields: &[ContactField]) -> Result<(), ParseError> { 51 | if fields.is_empty() { 52 | return Err(ParseError::ContactFieldMissing); 53 | } 54 | 55 | Ok(()) 56 | } 57 | 58 | fn validate_expires(fields: &[ExpiresField]) -> Result<(), ParseError> { 59 | if fields.is_empty() { 60 | return Err(ParseError::ExpiresFieldMissing); 61 | } 62 | if fields.len() > 1 { 63 | return Err(ParseError::ExpiresFieldMultiple); 64 | } 65 | 66 | Ok(()) 67 | } 68 | 69 | fn validate_preferred_languages(fields: &[PreferredLanguagesField]) -> Result<(), ParseError> { 70 | if fields.len() > 1 { 71 | return Err(ParseError::PreferredLanguagesFieldMultiple); 72 | } 73 | 74 | Ok(()) 75 | } 76 | 77 | pub(crate) fn new(fields: Vec, options: &SecurityTxtOptions) -> Result { 78 | let mut acknowledgments: Vec = vec![]; 79 | let mut canonical: Vec = vec![]; 80 | let mut contact: Vec = vec![]; 81 | let mut csaf: Vec = vec![]; 82 | let mut encryption: Vec = vec![]; 83 | let mut expires: Vec = vec![]; 84 | let mut extension: Vec = vec![]; 85 | let mut hiring: Vec = vec![]; 86 | let mut policy: Vec = vec![]; 87 | let mut preferred_languages: Vec = vec![]; 88 | 89 | for field in fields { 90 | let name = field.name.to_lowercase(); 91 | 92 | match &name[..] { 93 | "acknowledgments" => acknowledgments.push(AcknowledgmentsField::new(field.value)?), 94 | "canonical" => canonical.push(CanonicalField::new(field.value)?), 95 | "contact" => contact.push(ContactField::new(field.value)?), 96 | "csaf" => csaf.push(CsafField::new(field.value)?), 97 | "encryption" => encryption.push(EncryptionField::new(field.value)?), 98 | "expires" => expires.push(ExpiresField::new(field.value, options.now)?), 99 | "hiring" => hiring.push(HiringField::new(field.value)?), 100 | "policy" => policy.push(PolicyField::new(field.value)?), 101 | "preferred-languages" => preferred_languages.push(PreferredLanguagesField::new(field.value)?), 102 | _ => extension.push(ExtensionField::new(name, field.value.to_owned())?), 103 | } 104 | } 105 | 106 | Self::validate_contact_fields(&contact)?; 107 | Self::validate_expires(&expires)?; 108 | Self::validate_preferred_languages(&preferred_languages)?; 109 | 110 | Ok(SecurityTxt { 111 | acknowledgments, 112 | canonical, 113 | contact, 114 | csaf, 115 | encryption, 116 | expires: expires.pop().unwrap(), // checked in Self::validate_expires() 117 | extension, 118 | hiring, 119 | policy, 120 | preferred_languages: preferred_languages.pop(), 121 | }) 122 | } 123 | 124 | /// Parses a security.txt file as a string according to [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116). 125 | pub fn parse(text: &str) -> Result { 126 | let options = Default::default(); 127 | Self::parse_with(text, &options) 128 | } 129 | 130 | /// Parses a security.txt file as a string according to [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116). 131 | pub fn parse_with(text: &str, options: &SecurityTxtOptions) -> Result { 132 | let unsigned_parser = SecurityTxtParser::new(options); 133 | 134 | match unsigned_parser.parse(text) { 135 | Ok(fields) => { 136 | let fields: Vec = fields.into_iter().flatten().collect(); 137 | Self::new(fields, options) 138 | } 139 | _ => { 140 | let signed_parser = PGPCleartextMessageParser::new(options); 141 | let msg = signed_parser.parse(text)?; 142 | let fields = unsigned_parser.parse(&msg.cleartext)?; 143 | let fields: Vec = fields.into_iter().flatten().collect(); 144 | Self::new(fields, options) 145 | } 146 | } 147 | } 148 | } 149 | 150 | impl PartialOrd for SecurityTxt { 151 | #[inline] 152 | fn partial_cmp(&self, other: &Self) -> Option { 153 | self.expires.partial_cmp(&other.expires) 154 | } 155 | } 156 | 157 | impl FromStr for SecurityTxt { 158 | type Err = ParseError; 159 | 160 | #[inline] 161 | fn from_str(text: &str) -> Result { 162 | Self::parse(text) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /sectxtlib/src/fields.rs: -------------------------------------------------------------------------------- 1 | use super::parse_error::ParseError; 2 | use chrono::{DateTime, Utc}; 3 | use iri_string::types::IriString; 4 | use oxilangtag::{LanguageTag, LanguageTagParseError}; 5 | use std::cmp::Ordering; 6 | use valuable::{Valuable, Value, Visit}; 7 | 8 | macro_rules! IriStringImpl { 9 | ($structname:ident) => { 10 | impl $structname { 11 | pub(crate) fn new(uri: &str) -> Result { 12 | let uri = uri.trim().parse::()?; 13 | 14 | if uri.scheme_str() == "http" { 15 | return Err(ParseError::InsecureHTTP); 16 | } 17 | 18 | let log_value = uri.as_str().to_string(); 19 | 20 | Ok(Self { uri, log_value }) 21 | } 22 | } 23 | 24 | impl Valuable for $structname { 25 | fn as_value(&self) -> Value<'_> { 26 | self.log_value.as_value() 27 | } 28 | 29 | fn visit(&self, _visit: &mut dyn Visit) {} 30 | } 31 | }; 32 | } 33 | 34 | /// An [Acknowledgments field](https://www.rfc-editor.org/rfc/rfc9116#name-acknowledgments) links to a page where security researchers are recognized 35 | #[derive(Debug, PartialEq)] 36 | pub struct AcknowledgmentsField { 37 | /// The URI of the link according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 38 | pub uri: IriString, 39 | 40 | log_value: String, 41 | } 42 | IriStringImpl!(AcknowledgmentsField); 43 | 44 | /// A [Canonical field](https://www.rfc-editor.org/rfc/rfc9116#name-canonical) contains a canonical URI for the security.txt file 45 | #[derive(Debug, PartialEq)] 46 | pub struct CanonicalField { 47 | /// The URI of the link according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 48 | pub uri: IriString, 49 | 50 | log_value: String, 51 | } 52 | IriStringImpl!(CanonicalField); 53 | 54 | /// A [Contact field](https://www.rfc-editor.org/rfc/rfc9116#name-contact) contains contact information to use for reporting vulnerabilities 55 | #[derive(Debug, PartialEq)] 56 | pub struct ContactField { 57 | /// The URI of the link according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 58 | pub uri: IriString, 59 | 60 | log_value: String, 61 | } 62 | IriStringImpl!(ContactField); 63 | 64 | /// A [CSAF field](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#718-requirement-8-securitytxt) contains the canonical URI for the CSAF provider-metadata.json 65 | #[derive(Debug, PartialEq)] 66 | pub struct CsafField { 67 | /// The URI of the link according to the [CSAF Standard](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#718-requirement-8-securitytxt) 68 | pub uri: IriString, 69 | 70 | log_value: String, 71 | } 72 | IriStringImpl!(CsafField); 73 | 74 | /// An [Encryption field](https://www.rfc-editor.org/rfc/rfc9116#name-encryption) links to a key to be used for encrypted communication 75 | #[derive(Debug, PartialEq)] 76 | pub struct EncryptionField { 77 | /// The URI of the link according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 78 | pub uri: IriString, 79 | 80 | log_value: String, 81 | } 82 | IriStringImpl!(EncryptionField); 83 | 84 | /// The [Expires field](https://www.rfc-editor.org/rfc/rfc9116#name-expires) represents the date and time after which the security.txt file is considered stale 85 | #[derive(Debug, PartialEq)] 86 | pub struct ExpiresField { 87 | /// The date and time from which the security.txt file is considered stale 88 | pub datetime: DateTime, 89 | 90 | log_value: String, 91 | } 92 | 93 | impl ExpiresField { 94 | pub(crate) fn new(datetime: &str, now: DateTime) -> Result { 95 | let datetime: DateTime = datetime.trim().parse()?; 96 | 97 | if datetime < now { 98 | return Err(ParseError::ExpiresFieldExpired); 99 | } 100 | 101 | let log_value = datetime.to_rfc3339(); 102 | 103 | Ok(Self { datetime, log_value }) 104 | } 105 | } 106 | 107 | impl PartialOrd for ExpiresField { 108 | #[inline] 109 | fn partial_cmp(&self, other: &Self) -> Option { 110 | self.datetime.partial_cmp(&other.datetime) 111 | } 112 | } 113 | 114 | impl Valuable for ExpiresField { 115 | fn as_value(&self) -> Value<'_> { 116 | self.log_value.as_value() 117 | } 118 | 119 | fn visit(&self, _visit: &mut dyn Visit) {} 120 | } 121 | 122 | /// A [Hiring field](https://www.rfc-editor.org/rfc/rfc9116#name-hiring) links to the vendor's security-related job positions 123 | #[derive(Debug, PartialEq)] 124 | pub struct HiringField { 125 | /// The URI of the link according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 126 | pub uri: IriString, 127 | 128 | log_value: String, 129 | } 130 | IriStringImpl!(HiringField); 131 | 132 | /// A [Policy field](https://www.rfc-editor.org/rfc/rfc9116#name-policy) links to the security policy page 133 | #[derive(Debug, PartialEq)] 134 | pub struct PolicyField { 135 | /// The URI of the link according to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 136 | pub uri: IriString, 137 | 138 | log_value: String, 139 | } 140 | IriStringImpl!(PolicyField); 141 | 142 | /// The [Preferred-Languages field](https://www.rfc-editor.org/rfc/rfc9116#name-preferred-languages) lists the preferred languages for security reports 143 | #[derive(Debug, PartialEq)] 144 | pub struct PreferredLanguagesField { 145 | /// The set of preferred languages according to [RFC 5646](https://www.rfc-editor.org/rfc/rfc5646) 146 | pub languages: Vec>, 147 | 148 | log_value: String, 149 | } 150 | 151 | impl PreferredLanguagesField { 152 | pub(crate) fn new(languages: &str) -> Result { 153 | let languages = languages 154 | .split(',') 155 | .map(str::trim) 156 | .map(LanguageTag::parse_and_normalize) 157 | .collect::>, LanguageTagParseError>>()?; 158 | 159 | if languages.is_empty() { 160 | return Err(ParseError::IllegalField); 161 | } 162 | 163 | let log_value = languages.join(", "); 164 | 165 | Ok(Self { languages, log_value }) 166 | } 167 | } 168 | 169 | impl Valuable for PreferredLanguagesField { 170 | fn as_value(&self) -> Value<'_> { 171 | self.log_value.as_value() 172 | } 173 | 174 | fn visit(&self, _visit: &mut dyn Visit) {} 175 | } 176 | 177 | /// The "Extension" field acts as a catch-all for any fields not explicitly supported by this library 178 | /// 179 | /// This feature accommodates [section 2.4 on Extensibility](https://www.rfc-editor.org/rfc/rfc9116#name-extensibility) in the specification. 180 | #[derive(Debug, PartialEq, Valuable)] 181 | pub struct ExtensionField { 182 | /// Name of the extension field 183 | pub name: String, 184 | /// Value of the extension field 185 | pub value: String, 186 | } 187 | 188 | impl ExtensionField { 189 | pub(crate) fn new(name: String, value: String) -> Result { 190 | Ok(Self { name, value }) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /sectxtlib/src/parsers.rs: -------------------------------------------------------------------------------- 1 | use crate::{ParseError, SecurityTxtOptions}; 2 | 3 | use super::raw_field::RawField; 4 | 5 | use nom::{ 6 | branch::alt, 7 | bytes::complete::{take_while, take_while1}, 8 | character::complete::{char, crlf, satisfy}, 9 | combinator::{all_consuming, map, opt, recognize}, 10 | multi::{many0_count, many1}, 11 | sequence::{preceded, terminated, tuple}, 12 | IResult, 13 | }; 14 | 15 | pub(crate) struct SecurityTxtParser { 16 | _options: SecurityTxtOptions, 17 | } 18 | 19 | impl SecurityTxtParser { 20 | pub fn new(options: &SecurityTxtOptions) -> Self { 21 | Self { 22 | _options: options.clone(), 23 | } 24 | } 25 | 26 | pub fn parse<'a>(&'a self, text: &'a str) -> Result>>, ParseError> { 27 | let (_, msg) = self.body_parser(text)?; 28 | Ok(msg) 29 | } 30 | 31 | // body = signed / unsigned 32 | // signed is handled separately. 33 | fn body_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, Vec>>> { 34 | all_consuming(|x| self.unsigned_parser(x))(i) 35 | } 36 | 37 | // unsigned = *line (contact-field eol) ; one or more required 38 | // *line (expires-field eol) ; exactly one required 39 | // *line [lang-field eol] *line ; exactly one optional 40 | // ; order of fields within the file is not important 41 | // ; except that if contact-field appears more 42 | // ; than once, the order of those indicates 43 | // ; priority (see Section 3.5.3) 44 | fn unsigned_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, Vec>>> { 45 | many1(|x| self.line_parser(x))(i) 46 | } 47 | 48 | // line = [ (field / comment) ] eol 49 | fn line_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, Option>> { 50 | let field_parser_opt = map(|x| self.field_parser(x), Some); 51 | let comment_parser_opt = map(|x| self.comment_parser(x), |_| None); 52 | 53 | let (i, raw_field) = terminated(opt(alt((comment_parser_opt, field_parser_opt))), |x| self.eol_parser(x))(i)?; 54 | let flattened = raw_field.flatten(); 55 | Ok((i, flattened)) 56 | } 57 | 58 | // eol = *WSP [CR] LF 59 | fn eol_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 60 | recognize(tuple((take_while(is_wsp), opt(|x| self.cr_parser(x)), |x| { 61 | self.lf_parser(x) 62 | })))(i) 63 | } 64 | 65 | // field = ; optional fields 66 | // ack-field / 67 | // can-field / 68 | // contact-field / ; optional repeated instances 69 | // encryption-field / 70 | // hiring-field / 71 | // policy-field / 72 | // ext-field 73 | fn field_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, RawField<'a>> { 74 | self.ext_name_parser(i) 75 | } 76 | 77 | // fs = ":" 78 | fn fs_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, char> { 79 | char(':')(i) 80 | } 81 | 82 | // comment = "#" *(WSP / VCHAR / %x80-FFFFF) 83 | fn comment_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 84 | let matcher = |x| is_wsp(x) || is_vchar(x) || x >= '\u{80}'; 85 | preceded(char('#'), take_while(matcher))(i) 86 | } 87 | 88 | // ack-field = "Acknowledgments" fs SP uri 89 | // can-field = "Canonical" fs SP uri 90 | // contact-field = "Contact" fs SP uri 91 | // expires-field = "Expires" fs SP date-time 92 | // encryption-field = "Encryption" fs SP uri 93 | // hiring-field = "Hiring" fs SP uri 94 | // lang-field = "Preferred-Languages" fs SP lang-values 95 | // policy-field = "Policy" fs SP uri 96 | // date-time = < imported from Section 5.6 of [RFC3339] > 97 | // lang-tag = < Language-Tag from Section 2.1 of [RFC5646] > 98 | // lang-values = lang-tag *(*WSP "," *WSP lang-tag) 99 | // uri = < URI as per Section 3 of [RFC3986] > 100 | 101 | // ext-field = field-name fs SP unstructured 102 | fn ext_name_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, RawField<'a>> { 103 | let (i, (name, _, _, value)) = tuple(( 104 | |x| self.field_name_parser(x), 105 | |x| self.fs_parser(x), 106 | |x| self.sp_parser(x), 107 | |x| self.unstructured_parser(x), 108 | ))(i)?; 109 | Ok((i, RawField { name, value })) 110 | } 111 | 112 | // field-name = < imported from Section 3.6.8 of [RFC5322] > 113 | // field-name = 1*ftext 114 | fn field_name_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 115 | take_while1(is_ftext_char)(i) 116 | } 117 | 118 | // < imported from [RFC5322] > 119 | // unstructured = *([FWS] VCHAR) *WSP 120 | // Ommitted obsolete part. 121 | fn unstructured_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 122 | recognize(terminated( 123 | recognize(many0_count(preceded(opt(|x| self.fws_parser(x)), satisfy(is_vchar)))), 124 | take_while(is_wsp), 125 | ))(i) 126 | } 127 | 128 | // < imported from [RFC5322] > 129 | // FWS = [*WSP CRLF] 1*WSP 130 | // Ommitted obsolete part. 131 | fn fws_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 132 | recognize(preceded( 133 | opt(tuple((take_while(is_wsp), |x| self.crlf_parser(x)))), 134 | take_while1(is_wsp), 135 | ))(i) 136 | } 137 | 138 | fn cr_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, char> { 139 | satisfy(is_cr)(i) 140 | } 141 | 142 | // CRLF = CR LF 143 | // ; Internet standard newline 144 | fn crlf_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 145 | crlf(i) 146 | } 147 | 148 | fn lf_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, char> { 149 | satisfy(is_lf)(i) 150 | } 151 | 152 | // SP = %x20 153 | fn sp_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, char> { 154 | char(' ')(i) 155 | } 156 | } 157 | 158 | // field-name = < imported from Section 3.6.8 of [RFC5322] > 159 | // ftext = %d33-57 / ; Printable US-ASCII 160 | // %d59-126 ; characters not including 161 | // ; ":". 162 | fn is_ftext_char(i: char) -> bool { 163 | match i { 164 | '\x21'..='\x39' => true, // %d33-57 165 | '\x3B'..='\x7E' => true, // %d59-126 166 | _ => false, 167 | } 168 | } 169 | 170 | // CR = %x0D 171 | // ; carriage return 172 | fn is_cr(i: char) -> bool { 173 | i == '\r' 174 | } 175 | 176 | // LF = %x0A 177 | // ; linefeed 178 | fn is_lf(i: char) -> bool { 179 | i == '\n' 180 | } 181 | 182 | // VCHAR = %x21-7E 183 | // ; visible (printing) characters 184 | fn is_vchar(i: char) -> bool { 185 | matches!(i, '\x21'..='\x7E') 186 | } 187 | 188 | // WSP = SP / HTAB 189 | // ; white space 190 | fn is_wsp(i: char) -> bool { 191 | i == ' ' || i == '\t' 192 | } 193 | 194 | #[cfg(test)] 195 | mod tests { 196 | use super::*; 197 | use std::{fs, path::PathBuf}; 198 | 199 | fn get_tests_dir(category: &str) -> PathBuf { 200 | let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 201 | d.push(format!("resources/test/{category}")); 202 | d 203 | } 204 | 205 | fn run_tests_from_dir(dir: &str) { 206 | let unsigned_parser = SecurityTxtParser::new(&Default::default()); 207 | let paths = get_tests_dir(dir).read_dir().unwrap(); 208 | 209 | for path in paths { 210 | let file = path.unwrap().path(); 211 | println!("Input file: {:?}", file); 212 | let buf = fs::read_to_string(file).unwrap(); 213 | let txt = unsigned_parser.parse(&buf); 214 | assert!(txt.is_ok()); 215 | } 216 | } 217 | 218 | #[test] 219 | fn test_category_gen_unsigned() { 220 | run_tests_from_dir("gen_unsigned") 221 | } 222 | 223 | #[test] 224 | fn test_line_parser() { 225 | let unsigned_parser = SecurityTxtParser::new(&Default::default()); 226 | let test_vector = vec![ 227 | ("\n", None), 228 | ("\t \r\n", None), 229 | ("# This is a comment.\n", None), 230 | ( 231 | "foo: bar\r\n", 232 | Some(RawField { 233 | name: "foo", 234 | value: "bar", 235 | }), 236 | ), 237 | ]; 238 | 239 | for (input, result) in test_vector { 240 | assert_eq!(unsigned_parser.line_parser(input), Ok(("", result))); 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /sectxtlib/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod fields; 2 | mod parse_error; 3 | mod parsers; 4 | mod pgpcleartextmessage; 5 | mod raw_field; 6 | mod securitytxt; 7 | mod securitytxt_options; 8 | 9 | pub use fields::{ 10 | AcknowledgmentsField, CanonicalField, ContactField, EncryptionField, ExpiresField, ExtensionField, HiringField, 11 | PolicyField, PreferredLanguagesField, 12 | }; 13 | pub use parse_error::ParseError; 14 | pub use securitytxt::SecurityTxt; 15 | pub use securitytxt_options::SecurityTxtOptions; 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use crate::fields::CsafField; 20 | 21 | use super::*; 22 | use chrono::{DateTime, Datelike, Duration, SecondsFormat, TimeZone, Utc}; 23 | use std::{fs, path::PathBuf}; 24 | 25 | const URL: &str = "https://securitytxt.org/"; 26 | const INSECURE_URL: &str = "http://securitytxt.org/"; 27 | 28 | fn some_datetime() -> DateTime { 29 | DateTime::parse_from_rfc3339("2023-01-01T08:19:03.000Z").unwrap().into() 30 | } 31 | 32 | fn future_expires_str() -> String { 33 | (Utc::now() + Duration::days(365)).to_rfc3339_opts(SecondsFormat::Millis, true) 34 | } 35 | 36 | fn expires_dt(expires: &str) -> ExpiresField { 37 | ExpiresField::new(expires, some_datetime()).unwrap() 38 | } 39 | 40 | fn get_parse_options() -> SecurityTxtOptions { 41 | SecurityTxtOptions { 42 | now: some_datetime(), 43 | strict: true, 44 | } 45 | } 46 | 47 | fn get_tests_dir(category: &str) -> PathBuf { 48 | let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 49 | d.push(format!("resources/test/{category}")); 50 | d 51 | } 52 | 53 | #[test] 54 | fn test_contact_and_expires() { 55 | let expires = future_expires_str(); 56 | let file = format!("Contact: {URL}\nExpires: {expires}\n"); 57 | let sec = SecurityTxt { 58 | acknowledgments: vec![], 59 | canonical: vec![], 60 | contact: vec![ContactField::new(URL).unwrap()], 61 | csaf: vec![], 62 | encryption: vec![], 63 | expires: expires_dt(&expires), 64 | extension: vec![], 65 | hiring: vec![], 66 | policy: vec![], 67 | preferred_languages: None, 68 | }; 69 | 70 | assert_eq!(file.parse(), Ok(sec)); 71 | } 72 | 73 | #[test] 74 | fn test_comment() { 75 | let expires = future_expires_str(); 76 | let file = format!("# this is a comment\n#\nContact: {URL}\nExpires: {expires}\n#\n"); 77 | let sec = SecurityTxt { 78 | acknowledgments: vec![], 79 | canonical: vec![], 80 | contact: vec![ContactField::new(URL).unwrap()], 81 | csaf: vec![], 82 | encryption: vec![], 83 | expires: expires_dt(&expires), 84 | extension: vec![], 85 | hiring: vec![], 86 | policy: vec![], 87 | preferred_languages: None, 88 | }; 89 | 90 | assert_eq!(file.parse(), Ok(sec)); 91 | } 92 | 93 | #[test] 94 | fn test_newlines() { 95 | let expires = future_expires_str(); 96 | let file = format!("\n\n\nContact: {URL}\n\n\nExpires: {expires}\n\n\n"); 97 | let sec = SecurityTxt { 98 | acknowledgments: vec![], 99 | canonical: vec![], 100 | contact: vec![ContactField::new(URL).unwrap()], 101 | csaf: vec![], 102 | encryption: vec![], 103 | expires: expires_dt(&expires), 104 | extension: vec![], 105 | hiring: vec![], 106 | policy: vec![], 107 | preferred_languages: None, 108 | }; 109 | 110 | assert_eq!(file.parse(), Ok(sec)); 111 | } 112 | 113 | #[test] 114 | fn test_acknowledgements() { 115 | let expires = future_expires_str(); 116 | let file = format!("Contact: {URL}\nExpires: {expires}\nAcknowledgments: {URL}\n"); 117 | let sec = SecurityTxt { 118 | acknowledgments: vec![AcknowledgmentsField::new(URL).unwrap()], 119 | canonical: vec![], 120 | contact: vec![ContactField::new(URL).unwrap()], 121 | csaf: vec![], 122 | encryption: vec![], 123 | expires: expires_dt(&expires), 124 | extension: vec![], 125 | hiring: vec![], 126 | policy: vec![], 127 | preferred_languages: None, 128 | }; 129 | 130 | assert_eq!(file.parse(), Ok(sec)); 131 | } 132 | 133 | #[test] 134 | fn test_csaf() { 135 | let expires = future_expires_str(); 136 | let file = format!("Contact: {URL}\nExpires: {expires}\nCSAF: {URL}\n"); 137 | let sec = SecurityTxt { 138 | acknowledgments: vec![], 139 | canonical: vec![], 140 | contact: vec![ContactField::new(URL).unwrap()], 141 | csaf: vec![CsafField::new(URL).unwrap()], 142 | encryption: vec![], 143 | expires: expires_dt(&expires), 144 | extension: vec![], 145 | hiring: vec![], 146 | policy: vec![], 147 | preferred_languages: None, 148 | }; 149 | 150 | assert_eq!(file.parse(), Ok(sec)); 151 | } 152 | 153 | #[test] 154 | fn test_contact_missing() { 155 | let expires = future_expires_str(); 156 | let file = format!("Expires: {expires}\n"); 157 | 158 | assert_eq!(file.parse::(), Err(ParseError::ContactFieldMissing)); 159 | } 160 | 161 | #[test] 162 | fn test_expires_missing() { 163 | let file = format!("Contact: {URL}\n"); 164 | 165 | assert_eq!(file.parse::(), Err(ParseError::ExpiresFieldMissing)); 166 | } 167 | 168 | #[test] 169 | fn test_trailing_content() { 170 | let expires = future_expires_str(); 171 | let file = format!("Contact: {URL}\nExpires: {expires}\nfoo"); 172 | 173 | assert_eq!(file.parse::(), Err(ParseError::Malformed)); 174 | } 175 | 176 | #[test] 177 | fn test_preferred_languages() { 178 | let expires = future_expires_str(); 179 | let file = format!("Contact: {URL}\nExpires: {expires}\nPreferred-Languages: en, fr\n"); 180 | let sec = SecurityTxt { 181 | acknowledgments: vec![], 182 | canonical: vec![], 183 | contact: vec![ContactField::new(URL).unwrap()], 184 | csaf: vec![], 185 | encryption: vec![], 186 | expires: expires_dt(&expires), 187 | extension: vec![], 188 | hiring: vec![], 189 | policy: vec![], 190 | preferred_languages: Some(PreferredLanguagesField::new("en, fr").unwrap()), 191 | }; 192 | 193 | assert_eq!(file.parse::(), Ok(sec)); 194 | } 195 | 196 | #[test] 197 | fn test_preferred_languages_multiple() { 198 | let expires = future_expires_str(); 199 | let file = format!("Contact: {URL}\nExpires: {expires}\nPreferred-Languages: en\nPreferred-Languages: de\n"); 200 | 201 | assert_eq!( 202 | file.parse::(), 203 | Err(ParseError::PreferredLanguagesFieldMultiple) 204 | ); 205 | } 206 | 207 | #[test] 208 | fn test_expires_multiple() { 209 | let expires = future_expires_str(); 210 | let file = format!("Contact: {URL}\nExpires: {expires}\nExpires: {expires}\n"); 211 | 212 | assert_eq!(file.parse::(), Err(ParseError::ExpiresFieldMultiple)); 213 | } 214 | 215 | #[test] 216 | fn test_insecure_http() { 217 | let expires = future_expires_str(); 218 | let file = format!("Contact: {INSECURE_URL}\nExpires: {expires}\n"); 219 | 220 | assert_eq!(file.parse::(), Err(ParseError::InsecureHTTP)); 221 | } 222 | 223 | #[test] 224 | fn test_signed_contact() { 225 | let expires = future_expires_str(); 226 | let file = format!( 227 | "-----BEGIN PGP SIGNED MESSAGE-----\r 228 | Hash: SHA256\r 229 | \r 230 | Contact: {URL} 231 | Contact: {URL}\r 232 | Expires: {expires}\r 233 | -----BEGIN PGP SIGNATURE-----\r 234 | Version: GnuPG v2.2\r 235 | \r 236 | abcdefABCDEF/+==\r 237 | -----END PGP SIGNATURE-----\r 238 | " 239 | ); 240 | let sec = SecurityTxt { 241 | acknowledgments: vec![], 242 | canonical: vec![], 243 | contact: vec![ContactField::new(URL).unwrap(), ContactField::new(URL).unwrap()], 244 | csaf: vec![], 245 | encryption: vec![], 246 | expires: expires_dt(&expires), 247 | extension: vec![], 248 | hiring: vec![], 249 | policy: vec![], 250 | preferred_languages: None, 251 | }; 252 | 253 | assert_eq!(file.parse(), Ok(sec)); 254 | } 255 | 256 | fn _test_category(category: &str) { 257 | let paths = get_tests_dir(category).read_dir().unwrap(); 258 | 259 | for path in paths { 260 | let buf = fs::read_to_string(path.unwrap().path()).unwrap(); 261 | let parse_options = get_parse_options(); 262 | let txt = SecurityTxt::parse_with(&buf, &parse_options); 263 | assert_eq!(txt.is_ok(), true); 264 | } 265 | } 266 | 267 | #[test] 268 | fn test_category_valid_unsigned() { 269 | _test_category("valid_unsigned") 270 | } 271 | 272 | #[test] 273 | fn test_category_valid_signed() { 274 | _test_category("valid_signed") 275 | } 276 | 277 | #[test] 278 | fn test_category_gen_unsigned() { 279 | _test_category("gen_unsigned") 280 | } 281 | 282 | #[test] 283 | fn test_expires_non_z_time() { 284 | let next_year = Utc::now().year() + 1; 285 | let test_times = [ 286 | ( 287 | format!("{next_year}-08-30T00:00:00+00:00"), 288 | Utc.with_ymd_and_hms(next_year, 8, 30, 0, 0, 0), 289 | ), 290 | ( 291 | format!("{next_year}-08-30T12:34:56+00:00"), 292 | Utc.with_ymd_and_hms(next_year, 8, 30, 12, 34, 56), 293 | ), 294 | ( 295 | format!("{next_year}-08-30T02:00:00+02:00"), 296 | Utc.with_ymd_and_hms(next_year, 8, 30, 0, 0, 0), 297 | ), 298 | ( 299 | format!("{next_year}-08-30T02:00:00-02:00"), 300 | Utc.with_ymd_and_hms(next_year, 8, 30, 4, 0, 0), 301 | ), 302 | ]; 303 | 304 | for (expires_str, expected_dt) in &test_times { 305 | let file = format!("Contact: {URL}\nExpires: {expires_str}\n"); 306 | let sec = SecurityTxt { 307 | acknowledgments: vec![], 308 | canonical: vec![], 309 | contact: vec![ContactField::new(URL).unwrap()], 310 | csaf: vec![], 311 | encryption: vec![], 312 | expires: ExpiresField::new(expires_str, some_datetime()).unwrap(), 313 | extension: vec![], 314 | hiring: vec![], 315 | policy: vec![], 316 | preferred_languages: None, 317 | }; 318 | 319 | let parsed: SecurityTxt = file.parse().unwrap(); 320 | assert_eq!(parsed, sec); 321 | let expected_dt = expected_dt.single().unwrap(); 322 | assert_eq!(parsed.expires.datetime.timestamp(), expected_dt.timestamp()); 323 | assert_eq!( 324 | parsed.expires.datetime.timestamp_subsec_millis(), 325 | expected_dt.timestamp_subsec_millis() 326 | ); 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /sectxtlib/src/pgpcleartextmessage.rs: -------------------------------------------------------------------------------- 1 | use crate::SecurityTxtOptions; 2 | 3 | use super::parse_error::ParseError; 4 | 5 | use nom::{ 6 | branch::alt, 7 | bytes::complete::{tag, take_while, take_while1}, 8 | character::complete::{line_ending, none_of, one_of}, 9 | combinator::{all_consuming, opt, peek, recognize}, 10 | multi::{many0, many1, many1_count, separated_list1}, 11 | sequence::{delimited, preceded, separated_pair, terminated, tuple}, 12 | IResult, 13 | }; 14 | 15 | #[derive(Debug, PartialEq)] 16 | pub(crate) struct PGPSignature<'a> { 17 | pub signature: &'a str, 18 | pub keys: Vec<(&'a str, &'a str)>, 19 | } 20 | 21 | #[derive(Debug, PartialEq)] 22 | pub(crate) struct PGPCleartextMessage<'a> { 23 | pub hash_armor_headers: Vec>, 24 | pub cleartext: String, 25 | pub signature: PGPSignature<'a>, 26 | } 27 | 28 | impl PGPCleartextMessage<'_> {} 29 | 30 | pub(crate) struct PGPCleartextMessageParser { 31 | options: SecurityTxtOptions, 32 | } 33 | 34 | impl PGPCleartextMessageParser { 35 | pub fn new(options: &SecurityTxtOptions) -> Self { 36 | Self { 37 | options: options.clone(), 38 | } 39 | } 40 | 41 | pub fn parse<'a>(&'a self, text: &'a str) -> Result, ParseError> { 42 | let (_, msg) = self.signed_parser(text)?; 43 | Ok(msg) 44 | } 45 | 46 | fn lf_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 47 | match self.options.strict { 48 | true => line_ending(i), 49 | false => tag("\n")(i), 50 | } 51 | } 52 | 53 | // signed = cleartext-header 54 | // 1*(hash-header) 55 | // CRLF 56 | // cleartext 57 | // signature 58 | fn signed_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, PGPCleartextMessage<'a>> { 59 | let (_, (_, hash_armor_headers, _, cleartext, signature)) = all_consuming(tuple(( 60 | |x| self.cleartext_header_parser(x), 61 | many1(|x| self.hash_header_parser(x)), 62 | |x| self.lf_parser(x), 63 | |x| self.cleartext_parser(x), 64 | |x| self.signature_parser(x), 65 | )))(i)?; 66 | 67 | Ok(( 68 | i, 69 | PGPCleartextMessage { 70 | hash_armor_headers, 71 | cleartext, 72 | signature, 73 | }, 74 | )) 75 | } 76 | 77 | // cleartext-header = %s"-----BEGIN PGP SIGNED MESSAGE-----" CRLF 78 | fn cleartext_header_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 79 | terminated(tag("-----BEGIN PGP SIGNED MESSAGE-----"), |x| self.lf_parser(x))(i) 80 | } 81 | 82 | // hash-header = %s"Hash: " hash-alg *("," hash-alg) CRLF 83 | fn hash_header_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, Vec<&'a str>> { 84 | delimited( 85 | tag("Hash: "), 86 | separated_list1(tag(","), |x| self.hash_alg_parser(x)), 87 | |x| self.lf_parser(x), 88 | )(i) 89 | } 90 | 91 | // hash-alg = token 92 | // ; imported from RFC 2045; see RFC 4880 Section 93 | // ; 10.3.3 for a pointer to the registry of 94 | // ; valid values 95 | fn hash_alg_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 96 | self.token_parser(i) 97 | } 98 | 99 | // < Section 5.1 of [RFC2045] > 100 | // token := 1* 102 | fn token_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 103 | take_while1(is_token_char)(i) 104 | } 105 | 106 | // cleartext = *((line-dash / line-from / line-nodash) [CR] LF) 107 | // EOL is handled in branches. 108 | fn cleartext_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, String> { 109 | let (i, lines) = many0(alt((|x| self.line_dash_parser(x), |x| self.line_nodash_parser(x))))(i)?; 110 | Ok((i, lines.join(""))) 111 | } 112 | 113 | // line-dash = ("- ") "-" *UTF8-char-not-cr 114 | // ; MUST include initial "- " 115 | fn line_dash_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 116 | preceded( 117 | tag("- "), 118 | recognize(tuple(( 119 | one_of("-"), 120 | take_while(|x| x != '\r' && x != '\n'), 121 | line_ending, 122 | ))), 123 | )(i) 124 | } 125 | 126 | // line-nodash = ["- "] *UTF8-char-not-cr 127 | // ; MAY include initial "- " 128 | fn line_nodash_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 129 | preceded( 130 | opt(tag("- ")), 131 | recognize(tuple(( 132 | peek(none_of("-")), 133 | take_while(|x| x != '\r' && x != '\n'), 134 | line_ending, 135 | ))), 136 | )(i) 137 | } 138 | 139 | // signature = armor-header 140 | // armor-keys 141 | // CRLF 142 | // signature-data 143 | // armor-tail 144 | fn signature_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, PGPSignature<'a>> { 145 | let (i, (_, keys, _, signature, _)) = tuple(( 146 | |x| self.armor_header_parser(x), 147 | |x| self.armor_keys_parser(x), 148 | |x| self.lf_parser(x), 149 | |x| self.signature_data_parser(x), 150 | |x| self.armor_tail_parser(x), 151 | ))(i)?; 152 | 153 | Ok((i, PGPSignature { signature, keys })) 154 | } 155 | 156 | // armor-header = %s"-----BEGIN PGP SIGNATURE-----" CRLF 157 | fn armor_header_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 158 | terminated(tag("-----BEGIN PGP SIGNATURE-----"), |x| self.lf_parser(x))(i) 159 | } 160 | 161 | // armor-keys = *(token ": " *( VCHAR / WSP ) CRLF) 162 | // ; Armor Header Keys from RFC 4880 163 | fn armor_keys_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, Vec<(&'a str, &'a str)>> { 164 | many0(terminated( 165 | separated_pair( 166 | |x| self.token_parser(x), 167 | tag(": "), 168 | take_while(|x| is_vchar(x) || is_wsp(x)), 169 | ), 170 | |x| self.lf_parser(x), 171 | ))(i) 172 | } 173 | 174 | // armor-tail = %s"-----END PGP SIGNATURE-----" CRLF 175 | fn armor_tail_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 176 | terminated(tag("-----END PGP SIGNATURE-----"), |x| self.lf_parser(x))(i) 177 | } 178 | 179 | // signature-data = 1*(1*(ALPHA / DIGIT / "=" / "+" / "/") CRLF) 180 | // ; base64; see RFC 4648 181 | // ; includes RFC 4880 checksum 182 | fn signature_data_parser<'a>(&'a self, i: &'a str) -> IResult<&'a str, &'a str> { 183 | recognize(many1_count(terminated(take_while1(is_signature_data_char), |x| { 184 | self.lf_parser(x) 185 | })))(i) 186 | } 187 | } 188 | 189 | // < Section 5.1 of [RFC2045] > 190 | // tspecials := "(" / ")" / "<" / ">" / "@" / 191 | // "," / ";" / ":" / "\" / <"> 192 | // "/" / "[" / "]" / "?" / "=" 193 | // ; Must be in quoted-string, 194 | // ; to use within parameter values 195 | fn is_token_char(i: char) -> bool { 196 | let tspecials = "()<>@,;:\\\"/[]?="; 197 | i != ' ' && !i.is_ascii_control() && tspecials.find(i).is_none() 198 | } 199 | 200 | fn is_signature_data_char(i: char) -> bool { 201 | matches!(i, 'a'..='z' | 'A'..='Z' | '0'..='9' | '=' | '+' | '/') 202 | } 203 | 204 | // VCHAR = %x21-7E 205 | // ; visible (printing) characters 206 | fn is_vchar(i: char) -> bool { 207 | matches!(i, '\x21'..='\x7E') 208 | } 209 | 210 | // WSP = SP / HTAB 211 | // ; white space 212 | fn is_wsp(i: char) -> bool { 213 | i == ' ' || i == '\t' 214 | } 215 | 216 | #[cfg(test)] 217 | mod tests { 218 | use super::*; 219 | 220 | const SIGNATURE_DATA: &str = "iHUEARYKAB0WIQSsP2kEdoKDVFpSg6u3rK+YCkjapwUCY9qRaQAKCRC3rK+YCkja\r 221 | pwALAP9LEHSYMDW4h8QRHg4MwCzUdnbjBLIvpq4QTo3dIqCUPwEA31MsEf95OKCh\r 222 | MTHYHajOzjwpwlQVrjkK419igx4imgk=\r 223 | =KONn\r 224 | "; 225 | 226 | #[test] 227 | fn test_parse() { 228 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 229 | let txt = format!( 230 | "-----BEGIN PGP SIGNED MESSAGE-----\r 231 | Hash: SHA512\r 232 | \r 233 | Test\r 234 | - Test\r 235 | -----BEGIN PGP SIGNATURE-----\r 236 | \r 237 | {SIGNATURE_DATA}-----END PGP SIGNATURE-----\r 238 | " 239 | ); 240 | let msg = PGPCleartextMessage { 241 | hash_armor_headers: vec![vec!["SHA512"]], 242 | cleartext: "Test\r\nTest\r\n".into(), 243 | signature: PGPSignature { 244 | signature: SIGNATURE_DATA, 245 | keys: vec![], 246 | }, 247 | }; 248 | assert_eq!(signed_parser.parse(&txt), Ok(msg)); 249 | } 250 | 251 | #[test] 252 | fn test_hash_header_parser() { 253 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 254 | let test_vector = vec![ 255 | ("Hash: SHA512\r\n", vec!["SHA512"]), 256 | ("Hash: SHA256,SHA512\r\n", vec!["SHA256", "SHA512"]), 257 | ]; 258 | 259 | for (input, result) in test_vector { 260 | assert_eq!(signed_parser.hash_header_parser(input), Ok(("", result))); 261 | } 262 | } 263 | 264 | #[test] 265 | fn test_token_parser() { 266 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 267 | let test_vector = vec![("SHA512\r\n", "SHA512", "\r\n")]; 268 | 269 | for (input, result, leftover) in test_vector { 270 | assert_eq!(signed_parser.token_parser(input), Ok((leftover, result))); 271 | } 272 | } 273 | 274 | #[test] 275 | fn test_line_dash_parser() { 276 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 277 | let test_vector = vec![("- -test\r\n", "-test\r\n")]; 278 | 279 | for (input, result) in test_vector { 280 | assert_eq!(signed_parser.line_dash_parser(input), Ok(("", result))); 281 | } 282 | } 283 | 284 | #[test] 285 | fn test_line_nodash_parser() { 286 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 287 | let test_vector = vec![("test\r\n", "test\r\n")]; 288 | 289 | for (input, result) in test_vector { 290 | assert_eq!(signed_parser.line_nodash_parser(input), Ok(("", result))); 291 | } 292 | } 293 | 294 | #[test] 295 | fn test_signature_parser() { 296 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 297 | let input = format!( 298 | "-----BEGIN PGP SIGNATURE-----\r 299 | \r 300 | {SIGNATURE_DATA}-----END PGP SIGNATURE-----\r 301 | " 302 | ); 303 | let signature = PGPSignature { 304 | signature: SIGNATURE_DATA, 305 | keys: vec![], 306 | }; 307 | 308 | assert_eq!(signed_parser.signature_parser(&input), Ok(("", signature))); 309 | } 310 | 311 | #[test] 312 | fn test_armor_header_parser() { 313 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 314 | let input = "-----BEGIN PGP SIGNATURE-----\r\n"; 315 | assert_eq!( 316 | signed_parser.armor_header_parser(input), 317 | Ok(("", "-----BEGIN PGP SIGNATURE-----")) 318 | ); 319 | } 320 | 321 | #[test] 322 | fn test_armor_tail_parser() { 323 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 324 | let input = "-----END PGP SIGNATURE-----\r\n"; 325 | assert_eq!( 326 | signed_parser.armor_tail_parser(input), 327 | Ok(("", "-----END PGP SIGNATURE-----")) 328 | ); 329 | } 330 | 331 | #[test] 332 | fn test_armor_keys_parser() { 333 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 334 | let test_vector = vec![ 335 | ("", vec![]), 336 | ("test: \r\n", vec![("test", "")]), 337 | ("test: test\r\n", vec![("test", "test")]), 338 | ]; 339 | 340 | for (input, result) in test_vector { 341 | assert_eq!(signed_parser.armor_keys_parser(input), Ok(("", result))); 342 | } 343 | } 344 | 345 | #[test] 346 | fn test_signature_data_parser() { 347 | let signed_parser = PGPCleartextMessageParser::new(&Default::default()); 348 | let test_vector = vec![ 349 | "iHUEARYKAB0WIQSsP2kEdoKDVFpSg6u3rK+YCkjapwUCY9qRaQAKCRC3rK+YCkja\r\npwALAP9LEHSYMDW4h8QRHg4MwCzUdnbjBLIvpq4QTo3dIqCUPwEA31MsEf95OKCh\r\nMTHYHajOzjwpwlQVrjkK419igx4imgk\r\n=KONn\r\n", 350 | ]; 351 | 352 | for input in test_vector { 353 | assert_eq!(signed_parser.signature_data_parser(input), Ok(("", input))); 354 | } 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.25.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 | 20 | [[package]] 21 | name = "afl" 22 | version = "0.17.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "2027b09e36bf321ace7af43a23df3d46dae645b855be337b0b6582c79ad53769" 25 | dependencies = [ 26 | "home", 27 | "libc", 28 | "rustc_version", 29 | "xdg", 30 | ] 31 | 32 | [[package]] 33 | name = "aho-corasick" 34 | version = "1.1.4" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" 37 | dependencies = [ 38 | "memchr", 39 | ] 40 | 41 | [[package]] 42 | name = "android_system_properties" 43 | version = "0.1.5" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 46 | dependencies = [ 47 | "libc", 48 | ] 49 | 50 | [[package]] 51 | name = "anstream" 52 | version = "0.6.21" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" 55 | dependencies = [ 56 | "anstyle", 57 | "anstyle-parse", 58 | "anstyle-query", 59 | "anstyle-wincon", 60 | "colorchoice", 61 | "is_terminal_polyfill", 62 | "utf8parse", 63 | ] 64 | 65 | [[package]] 66 | name = "anstyle" 67 | version = "1.0.13" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" 70 | 71 | [[package]] 72 | name = "anstyle-parse" 73 | version = "0.2.7" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 76 | dependencies = [ 77 | "utf8parse", 78 | ] 79 | 80 | [[package]] 81 | name = "anstyle-query" 82 | version = "1.1.5" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" 85 | dependencies = [ 86 | "windows-sys 0.61.2", 87 | ] 88 | 89 | [[package]] 90 | name = "anstyle-wincon" 91 | version = "3.0.11" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" 94 | dependencies = [ 95 | "anstyle", 96 | "once_cell_polyfill", 97 | "windows-sys 0.61.2", 98 | ] 99 | 100 | [[package]] 101 | name = "anyhow" 102 | version = "1.0.100" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" 105 | 106 | [[package]] 107 | name = "argh" 108 | version = "0.1.13" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240" 111 | dependencies = [ 112 | "argh_derive", 113 | "argh_shared", 114 | "rust-fuzzy-search", 115 | ] 116 | 117 | [[package]] 118 | name = "argh_derive" 119 | version = "0.1.13" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803" 122 | dependencies = [ 123 | "argh_shared", 124 | "proc-macro2", 125 | "quote", 126 | "syn", 127 | ] 128 | 129 | [[package]] 130 | name = "argh_shared" 131 | version = "0.1.13" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6" 134 | dependencies = [ 135 | "serde", 136 | ] 137 | 138 | [[package]] 139 | name = "atomic-waker" 140 | version = "1.1.2" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 143 | 144 | [[package]] 145 | name = "autocfg" 146 | version = "1.5.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 149 | 150 | [[package]] 151 | name = "backtrace" 152 | version = "0.3.76" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" 155 | dependencies = [ 156 | "addr2line", 157 | "cfg-if", 158 | "libc", 159 | "miniz_oxide", 160 | "object", 161 | "rustc-demangle", 162 | "windows-link", 163 | ] 164 | 165 | [[package]] 166 | name = "base64" 167 | version = "0.22.1" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 170 | 171 | [[package]] 172 | name = "bitflags" 173 | version = "2.10.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 176 | 177 | [[package]] 178 | name = "block2" 179 | version = "0.6.2" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" 182 | dependencies = [ 183 | "objc2", 184 | ] 185 | 186 | [[package]] 187 | name = "bumpalo" 188 | version = "3.19.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" 191 | 192 | [[package]] 193 | name = "bytes" 194 | version = "1.11.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 197 | 198 | [[package]] 199 | name = "cc" 200 | version = "1.2.48" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" 203 | dependencies = [ 204 | "find-msvc-tools", 205 | "shlex", 206 | ] 207 | 208 | [[package]] 209 | name = "cfg-if" 210 | version = "1.0.4" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 213 | 214 | [[package]] 215 | name = "cfg_aliases" 216 | version = "0.2.1" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 219 | 220 | [[package]] 221 | name = "chrono" 222 | version = "0.4.42" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" 225 | dependencies = [ 226 | "iana-time-zone", 227 | "js-sys", 228 | "num-traits", 229 | "wasm-bindgen", 230 | "windows-link", 231 | ] 232 | 233 | [[package]] 234 | name = "colorchoice" 235 | version = "1.0.4" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 238 | 239 | [[package]] 240 | name = "core-foundation" 241 | version = "0.9.4" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 244 | dependencies = [ 245 | "core-foundation-sys", 246 | "libc", 247 | ] 248 | 249 | [[package]] 250 | name = "core-foundation-sys" 251 | version = "0.8.7" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 254 | 255 | [[package]] 256 | name = "dispatch2" 257 | version = "0.3.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" 260 | dependencies = [ 261 | "bitflags", 262 | "objc2", 263 | ] 264 | 265 | [[package]] 266 | name = "displaydoc" 267 | version = "0.2.5" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 270 | dependencies = [ 271 | "proc-macro2", 272 | "quote", 273 | "syn", 274 | ] 275 | 276 | [[package]] 277 | name = "encoding_rs" 278 | version = "0.8.35" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 281 | dependencies = [ 282 | "cfg-if", 283 | ] 284 | 285 | [[package]] 286 | name = "equivalent" 287 | version = "1.0.2" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 290 | 291 | [[package]] 292 | name = "errno" 293 | version = "0.3.14" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 296 | dependencies = [ 297 | "libc", 298 | "windows-sys 0.61.2", 299 | ] 300 | 301 | [[package]] 302 | name = "fastrand" 303 | version = "2.3.0" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 306 | 307 | [[package]] 308 | name = "find-msvc-tools" 309 | version = "0.1.5" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 312 | 313 | [[package]] 314 | name = "fnv" 315 | version = "1.0.7" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 318 | 319 | [[package]] 320 | name = "foreign-types" 321 | version = "0.3.2" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 324 | dependencies = [ 325 | "foreign-types-shared", 326 | ] 327 | 328 | [[package]] 329 | name = "foreign-types-shared" 330 | version = "0.1.1" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 333 | 334 | [[package]] 335 | name = "form_urlencoded" 336 | version = "1.2.2" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 339 | dependencies = [ 340 | "percent-encoding", 341 | ] 342 | 343 | [[package]] 344 | name = "futures" 345 | version = "0.3.31" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 348 | dependencies = [ 349 | "futures-channel", 350 | "futures-core", 351 | "futures-executor", 352 | "futures-io", 353 | "futures-sink", 354 | "futures-task", 355 | "futures-util", 356 | ] 357 | 358 | [[package]] 359 | name = "futures-channel" 360 | version = "0.3.31" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 363 | dependencies = [ 364 | "futures-core", 365 | "futures-sink", 366 | ] 367 | 368 | [[package]] 369 | name = "futures-core" 370 | version = "0.3.31" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 373 | 374 | [[package]] 375 | name = "futures-executor" 376 | version = "0.3.31" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 379 | dependencies = [ 380 | "futures-core", 381 | "futures-task", 382 | "futures-util", 383 | ] 384 | 385 | [[package]] 386 | name = "futures-io" 387 | version = "0.3.31" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 390 | 391 | [[package]] 392 | name = "futures-macro" 393 | version = "0.3.31" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 396 | dependencies = [ 397 | "proc-macro2", 398 | "quote", 399 | "syn", 400 | ] 401 | 402 | [[package]] 403 | name = "futures-sink" 404 | version = "0.3.31" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 407 | 408 | [[package]] 409 | name = "futures-task" 410 | version = "0.3.31" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 413 | 414 | [[package]] 415 | name = "futures-util" 416 | version = "0.3.31" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 419 | dependencies = [ 420 | "futures-channel", 421 | "futures-core", 422 | "futures-io", 423 | "futures-macro", 424 | "futures-sink", 425 | "futures-task", 426 | "memchr", 427 | "pin-project-lite", 428 | "pin-utils", 429 | "slab", 430 | ] 431 | 432 | [[package]] 433 | name = "getrandom" 434 | version = "0.2.16" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 437 | dependencies = [ 438 | "cfg-if", 439 | "libc", 440 | "wasi", 441 | ] 442 | 443 | [[package]] 444 | name = "getrandom" 445 | version = "0.3.4" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" 448 | dependencies = [ 449 | "cfg-if", 450 | "libc", 451 | "r-efi", 452 | "wasip2", 453 | ] 454 | 455 | [[package]] 456 | name = "gimli" 457 | version = "0.32.3" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" 460 | 461 | [[package]] 462 | name = "h2" 463 | version = "0.4.12" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" 466 | dependencies = [ 467 | "atomic-waker", 468 | "bytes", 469 | "fnv", 470 | "futures-core", 471 | "futures-sink", 472 | "http", 473 | "indexmap", 474 | "slab", 475 | "tokio", 476 | "tokio-util", 477 | "tracing", 478 | ] 479 | 480 | [[package]] 481 | name = "hashbrown" 482 | version = "0.16.1" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 485 | 486 | [[package]] 487 | name = "home" 488 | version = "0.5.12" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" 491 | dependencies = [ 492 | "windows-sys 0.61.2", 493 | ] 494 | 495 | [[package]] 496 | name = "http" 497 | version = "1.4.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" 500 | dependencies = [ 501 | "bytes", 502 | "itoa", 503 | ] 504 | 505 | [[package]] 506 | name = "http-body" 507 | version = "1.0.1" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 510 | dependencies = [ 511 | "bytes", 512 | "http", 513 | ] 514 | 515 | [[package]] 516 | name = "http-body-util" 517 | version = "0.1.3" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 520 | dependencies = [ 521 | "bytes", 522 | "futures-core", 523 | "http", 524 | "http-body", 525 | "pin-project-lite", 526 | ] 527 | 528 | [[package]] 529 | name = "httparse" 530 | version = "1.10.1" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 533 | 534 | [[package]] 535 | name = "human-panic" 536 | version = "2.0.4" 537 | source = "registry+https://github.com/rust-lang/crates.io-index" 538 | checksum = "9a8a07a0957cd4a3cad4a1e4ca7cd5ea07fcacef6ebe2e5d0c7935bfc95120d8" 539 | dependencies = [ 540 | "anstream", 541 | "anstyle", 542 | "backtrace", 543 | "os_info", 544 | "serde", 545 | "serde_derive", 546 | "toml", 547 | "uuid", 548 | ] 549 | 550 | [[package]] 551 | name = "hyper" 552 | version = "1.8.1" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" 555 | dependencies = [ 556 | "atomic-waker", 557 | "bytes", 558 | "futures-channel", 559 | "futures-core", 560 | "h2", 561 | "http", 562 | "http-body", 563 | "httparse", 564 | "itoa", 565 | "pin-project-lite", 566 | "pin-utils", 567 | "smallvec", 568 | "tokio", 569 | "want", 570 | ] 571 | 572 | [[package]] 573 | name = "hyper-rustls" 574 | version = "0.27.7" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" 577 | dependencies = [ 578 | "http", 579 | "hyper", 580 | "hyper-util", 581 | "rustls", 582 | "rustls-pki-types", 583 | "tokio", 584 | "tokio-rustls", 585 | "tower-service", 586 | ] 587 | 588 | [[package]] 589 | name = "hyper-tls" 590 | version = "0.6.0" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 593 | dependencies = [ 594 | "bytes", 595 | "http-body-util", 596 | "hyper", 597 | "hyper-util", 598 | "native-tls", 599 | "tokio", 600 | "tokio-native-tls", 601 | "tower-service", 602 | ] 603 | 604 | [[package]] 605 | name = "hyper-util" 606 | version = "0.1.18" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" 609 | dependencies = [ 610 | "base64", 611 | "bytes", 612 | "futures-channel", 613 | "futures-core", 614 | "futures-util", 615 | "http", 616 | "http-body", 617 | "hyper", 618 | "ipnet", 619 | "libc", 620 | "percent-encoding", 621 | "pin-project-lite", 622 | "socket2", 623 | "system-configuration", 624 | "tokio", 625 | "tower-service", 626 | "tracing", 627 | "windows-registry", 628 | ] 629 | 630 | [[package]] 631 | name = "iana-time-zone" 632 | version = "0.1.64" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" 635 | dependencies = [ 636 | "android_system_properties", 637 | "core-foundation-sys", 638 | "iana-time-zone-haiku", 639 | "js-sys", 640 | "log", 641 | "wasm-bindgen", 642 | "windows-core", 643 | ] 644 | 645 | [[package]] 646 | name = "iana-time-zone-haiku" 647 | version = "0.1.2" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 650 | dependencies = [ 651 | "cc", 652 | ] 653 | 654 | [[package]] 655 | name = "icu_collections" 656 | version = "2.1.1" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" 659 | dependencies = [ 660 | "displaydoc", 661 | "potential_utf", 662 | "yoke", 663 | "zerofrom", 664 | "zerovec", 665 | ] 666 | 667 | [[package]] 668 | name = "icu_locale_core" 669 | version = "2.1.1" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" 672 | dependencies = [ 673 | "displaydoc", 674 | "litemap", 675 | "tinystr", 676 | "writeable", 677 | "zerovec", 678 | ] 679 | 680 | [[package]] 681 | name = "icu_normalizer" 682 | version = "2.1.1" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" 685 | dependencies = [ 686 | "icu_collections", 687 | "icu_normalizer_data", 688 | "icu_properties", 689 | "icu_provider", 690 | "smallvec", 691 | "zerovec", 692 | ] 693 | 694 | [[package]] 695 | name = "icu_normalizer_data" 696 | version = "2.1.1" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" 699 | 700 | [[package]] 701 | name = "icu_properties" 702 | version = "2.1.1" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" 705 | dependencies = [ 706 | "icu_collections", 707 | "icu_locale_core", 708 | "icu_properties_data", 709 | "icu_provider", 710 | "zerotrie", 711 | "zerovec", 712 | ] 713 | 714 | [[package]] 715 | name = "icu_properties_data" 716 | version = "2.1.1" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" 719 | 720 | [[package]] 721 | name = "icu_provider" 722 | version = "2.1.1" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" 725 | dependencies = [ 726 | "displaydoc", 727 | "icu_locale_core", 728 | "writeable", 729 | "yoke", 730 | "zerofrom", 731 | "zerotrie", 732 | "zerovec", 733 | ] 734 | 735 | [[package]] 736 | name = "idna" 737 | version = "1.1.0" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 740 | dependencies = [ 741 | "idna_adapter", 742 | "smallvec", 743 | "utf8_iter", 744 | ] 745 | 746 | [[package]] 747 | name = "idna_adapter" 748 | version = "1.2.1" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 751 | dependencies = [ 752 | "icu_normalizer", 753 | "icu_properties", 754 | ] 755 | 756 | [[package]] 757 | name = "indexmap" 758 | version = "2.12.1" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" 761 | dependencies = [ 762 | "equivalent", 763 | "hashbrown", 764 | ] 765 | 766 | [[package]] 767 | name = "ipnet" 768 | version = "2.11.0" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 771 | 772 | [[package]] 773 | name = "iri-string" 774 | version = "0.7.9" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" 777 | dependencies = [ 778 | "memchr", 779 | "serde", 780 | ] 781 | 782 | [[package]] 783 | name = "is_terminal_polyfill" 784 | version = "1.70.2" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" 787 | 788 | [[package]] 789 | name = "itoa" 790 | version = "1.0.15" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 793 | 794 | [[package]] 795 | name = "js-sys" 796 | version = "0.3.83" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" 799 | dependencies = [ 800 | "once_cell", 801 | "wasm-bindgen", 802 | ] 803 | 804 | [[package]] 805 | name = "lazy_static" 806 | version = "1.5.0" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 809 | 810 | [[package]] 811 | name = "libc" 812 | version = "0.2.177" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 815 | 816 | [[package]] 817 | name = "linux-raw-sys" 818 | version = "0.11.0" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 821 | 822 | [[package]] 823 | name = "litemap" 824 | version = "0.8.1" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 827 | 828 | [[package]] 829 | name = "log" 830 | version = "0.4.28" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 833 | 834 | [[package]] 835 | name = "matchers" 836 | version = "0.2.0" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" 839 | dependencies = [ 840 | "regex-automata", 841 | ] 842 | 843 | [[package]] 844 | name = "memchr" 845 | version = "2.7.6" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 848 | 849 | [[package]] 850 | name = "mime" 851 | version = "0.3.17" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 854 | 855 | [[package]] 856 | name = "minimal-lexical" 857 | version = "0.2.1" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 860 | 861 | [[package]] 862 | name = "miniz_oxide" 863 | version = "0.8.9" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 866 | dependencies = [ 867 | "adler2", 868 | ] 869 | 870 | [[package]] 871 | name = "mio" 872 | version = "1.1.0" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" 875 | dependencies = [ 876 | "libc", 877 | "wasi", 878 | "windows-sys 0.61.2", 879 | ] 880 | 881 | [[package]] 882 | name = "native-tls" 883 | version = "0.2.14" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" 886 | dependencies = [ 887 | "libc", 888 | "log", 889 | "openssl", 890 | "openssl-probe", 891 | "openssl-sys", 892 | "schannel", 893 | "security-framework", 894 | "security-framework-sys", 895 | "tempfile", 896 | ] 897 | 898 | [[package]] 899 | name = "nix" 900 | version = "0.30.1" 901 | source = "registry+https://github.com/rust-lang/crates.io-index" 902 | checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" 903 | dependencies = [ 904 | "bitflags", 905 | "cfg-if", 906 | "cfg_aliases", 907 | "libc", 908 | ] 909 | 910 | [[package]] 911 | name = "nom" 912 | version = "7.1.3" 913 | source = "registry+https://github.com/rust-lang/crates.io-index" 914 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 915 | dependencies = [ 916 | "memchr", 917 | "minimal-lexical", 918 | ] 919 | 920 | [[package]] 921 | name = "nu-ansi-term" 922 | version = "0.50.3" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" 925 | dependencies = [ 926 | "windows-sys 0.61.2", 927 | ] 928 | 929 | [[package]] 930 | name = "num-traits" 931 | version = "0.2.19" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 934 | dependencies = [ 935 | "autocfg", 936 | ] 937 | 938 | [[package]] 939 | name = "objc2" 940 | version = "0.6.3" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" 943 | dependencies = [ 944 | "objc2-encode", 945 | ] 946 | 947 | [[package]] 948 | name = "objc2-cloud-kit" 949 | version = "0.3.2" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" 952 | dependencies = [ 953 | "bitflags", 954 | "objc2", 955 | "objc2-foundation", 956 | ] 957 | 958 | [[package]] 959 | name = "objc2-core-data" 960 | version = "0.3.2" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" 963 | dependencies = [ 964 | "objc2", 965 | "objc2-foundation", 966 | ] 967 | 968 | [[package]] 969 | name = "objc2-core-foundation" 970 | version = "0.3.2" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" 973 | dependencies = [ 974 | "bitflags", 975 | "dispatch2", 976 | "objc2", 977 | ] 978 | 979 | [[package]] 980 | name = "objc2-core-graphics" 981 | version = "0.3.2" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" 984 | dependencies = [ 985 | "bitflags", 986 | "dispatch2", 987 | "objc2", 988 | "objc2-core-foundation", 989 | "objc2-io-surface", 990 | ] 991 | 992 | [[package]] 993 | name = "objc2-core-image" 994 | version = "0.3.2" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" 997 | dependencies = [ 998 | "objc2", 999 | "objc2-foundation", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "objc2-core-location" 1004 | version = "0.3.2" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" 1007 | dependencies = [ 1008 | "objc2", 1009 | "objc2-foundation", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "objc2-core-text" 1014 | version = "0.3.2" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" 1017 | dependencies = [ 1018 | "bitflags", 1019 | "objc2", 1020 | "objc2-core-foundation", 1021 | "objc2-core-graphics", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "objc2-encode" 1026 | version = "4.1.0" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" 1029 | 1030 | [[package]] 1031 | name = "objc2-foundation" 1032 | version = "0.3.2" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" 1035 | dependencies = [ 1036 | "bitflags", 1037 | "block2", 1038 | "libc", 1039 | "objc2", 1040 | "objc2-core-foundation", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "objc2-io-surface" 1045 | version = "0.3.2" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" 1048 | dependencies = [ 1049 | "bitflags", 1050 | "objc2", 1051 | "objc2-core-foundation", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "objc2-quartz-core" 1056 | version = "0.3.2" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" 1059 | dependencies = [ 1060 | "bitflags", 1061 | "objc2", 1062 | "objc2-core-foundation", 1063 | "objc2-foundation", 1064 | ] 1065 | 1066 | [[package]] 1067 | name = "objc2-ui-kit" 1068 | version = "0.3.2" 1069 | source = "registry+https://github.com/rust-lang/crates.io-index" 1070 | checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" 1071 | dependencies = [ 1072 | "bitflags", 1073 | "block2", 1074 | "objc2", 1075 | "objc2-cloud-kit", 1076 | "objc2-core-data", 1077 | "objc2-core-foundation", 1078 | "objc2-core-graphics", 1079 | "objc2-core-image", 1080 | "objc2-core-location", 1081 | "objc2-core-text", 1082 | "objc2-foundation", 1083 | "objc2-quartz-core", 1084 | "objc2-user-notifications", 1085 | ] 1086 | 1087 | [[package]] 1088 | name = "objc2-user-notifications" 1089 | version = "0.3.2" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" 1092 | dependencies = [ 1093 | "objc2", 1094 | "objc2-foundation", 1095 | ] 1096 | 1097 | [[package]] 1098 | name = "object" 1099 | version = "0.37.3" 1100 | source = "registry+https://github.com/rust-lang/crates.io-index" 1101 | checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" 1102 | dependencies = [ 1103 | "memchr", 1104 | ] 1105 | 1106 | [[package]] 1107 | name = "once_cell" 1108 | version = "1.21.3" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1111 | 1112 | [[package]] 1113 | name = "once_cell_polyfill" 1114 | version = "1.70.2" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" 1117 | 1118 | [[package]] 1119 | name = "openssl" 1120 | version = "0.10.75" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" 1123 | dependencies = [ 1124 | "bitflags", 1125 | "cfg-if", 1126 | "foreign-types", 1127 | "libc", 1128 | "once_cell", 1129 | "openssl-macros", 1130 | "openssl-sys", 1131 | ] 1132 | 1133 | [[package]] 1134 | name = "openssl-macros" 1135 | version = "0.1.1" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 1138 | dependencies = [ 1139 | "proc-macro2", 1140 | "quote", 1141 | "syn", 1142 | ] 1143 | 1144 | [[package]] 1145 | name = "openssl-probe" 1146 | version = "0.1.6" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1149 | 1150 | [[package]] 1151 | name = "openssl-sys" 1152 | version = "0.9.111" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" 1155 | dependencies = [ 1156 | "cc", 1157 | "libc", 1158 | "pkg-config", 1159 | "vcpkg", 1160 | ] 1161 | 1162 | [[package]] 1163 | name = "os_info" 1164 | version = "3.13.0" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | checksum = "7c39b5918402d564846d5aba164c09a66cc88d232179dfd3e3c619a25a268392" 1167 | dependencies = [ 1168 | "android_system_properties", 1169 | "log", 1170 | "nix", 1171 | "objc2", 1172 | "objc2-foundation", 1173 | "objc2-ui-kit", 1174 | "serde", 1175 | "windows-sys 0.61.2", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "oxilangtag" 1180 | version = "0.1.5" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "23f3f87617a86af77fa3691e6350483e7154c2ead9f1261b75130e21ca0f8acb" 1183 | dependencies = [ 1184 | "serde", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "percent-encoding" 1189 | version = "2.3.2" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1192 | 1193 | [[package]] 1194 | name = "pin-project-lite" 1195 | version = "0.2.16" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1198 | 1199 | [[package]] 1200 | name = "pin-utils" 1201 | version = "0.1.0" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1204 | 1205 | [[package]] 1206 | name = "pkg-config" 1207 | version = "0.3.32" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 1210 | 1211 | [[package]] 1212 | name = "potential_utf" 1213 | version = "0.1.4" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 1216 | dependencies = [ 1217 | "zerovec", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "proc-macro2" 1222 | version = "1.0.103" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 1225 | dependencies = [ 1226 | "unicode-ident", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "quote" 1231 | version = "1.0.42" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 1234 | dependencies = [ 1235 | "proc-macro2", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "r-efi" 1240 | version = "5.3.0" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1243 | 1244 | [[package]] 1245 | name = "regex-automata" 1246 | version = "0.4.13" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" 1249 | dependencies = [ 1250 | "aho-corasick", 1251 | "memchr", 1252 | "regex-syntax", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "regex-syntax" 1257 | version = "0.8.8" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 1260 | 1261 | [[package]] 1262 | name = "reqwest" 1263 | version = "0.12.24" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" 1266 | dependencies = [ 1267 | "base64", 1268 | "bytes", 1269 | "encoding_rs", 1270 | "futures-core", 1271 | "h2", 1272 | "http", 1273 | "http-body", 1274 | "http-body-util", 1275 | "hyper", 1276 | "hyper-rustls", 1277 | "hyper-tls", 1278 | "hyper-util", 1279 | "js-sys", 1280 | "log", 1281 | "mime", 1282 | "native-tls", 1283 | "percent-encoding", 1284 | "pin-project-lite", 1285 | "rustls-pki-types", 1286 | "serde", 1287 | "serde_json", 1288 | "serde_urlencoded", 1289 | "sync_wrapper", 1290 | "tokio", 1291 | "tokio-native-tls", 1292 | "tower", 1293 | "tower-http", 1294 | "tower-service", 1295 | "url", 1296 | "wasm-bindgen", 1297 | "wasm-bindgen-futures", 1298 | "web-sys", 1299 | ] 1300 | 1301 | [[package]] 1302 | name = "ring" 1303 | version = "0.17.14" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1306 | dependencies = [ 1307 | "cc", 1308 | "cfg-if", 1309 | "getrandom 0.2.16", 1310 | "libc", 1311 | "untrusted", 1312 | "windows-sys 0.52.0", 1313 | ] 1314 | 1315 | [[package]] 1316 | name = "rust-fuzzy-search" 1317 | version = "0.1.1" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" 1320 | 1321 | [[package]] 1322 | name = "rustc-demangle" 1323 | version = "0.1.26" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" 1326 | 1327 | [[package]] 1328 | name = "rustc_version" 1329 | version = "0.4.1" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1332 | dependencies = [ 1333 | "semver", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "rustix" 1338 | version = "1.1.2" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 1341 | dependencies = [ 1342 | "bitflags", 1343 | "errno", 1344 | "libc", 1345 | "linux-raw-sys", 1346 | "windows-sys 0.61.2", 1347 | ] 1348 | 1349 | [[package]] 1350 | name = "rustls" 1351 | version = "0.23.35" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" 1354 | dependencies = [ 1355 | "once_cell", 1356 | "rustls-pki-types", 1357 | "rustls-webpki", 1358 | "subtle", 1359 | "zeroize", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "rustls-pki-types" 1364 | version = "1.13.1" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" 1367 | dependencies = [ 1368 | "zeroize", 1369 | ] 1370 | 1371 | [[package]] 1372 | name = "rustls-webpki" 1373 | version = "0.103.8" 1374 | source = "registry+https://github.com/rust-lang/crates.io-index" 1375 | checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" 1376 | dependencies = [ 1377 | "ring", 1378 | "rustls-pki-types", 1379 | "untrusted", 1380 | ] 1381 | 1382 | [[package]] 1383 | name = "rustversion" 1384 | version = "1.0.22" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 1387 | 1388 | [[package]] 1389 | name = "ryu" 1390 | version = "1.0.20" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1393 | 1394 | [[package]] 1395 | name = "schannel" 1396 | version = "0.1.28" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" 1399 | dependencies = [ 1400 | "windows-sys 0.61.2", 1401 | ] 1402 | 1403 | [[package]] 1404 | name = "sectxt" 1405 | version = "0.4.0" 1406 | dependencies = [ 1407 | "anyhow", 1408 | "argh", 1409 | "futures", 1410 | "human-panic", 1411 | "lazy_static", 1412 | "reqwest", 1413 | "sectxtlib", 1414 | "tokio", 1415 | "tracing", 1416 | "tracing-subscriber", 1417 | "url", 1418 | "valuable", 1419 | ] 1420 | 1421 | [[package]] 1422 | name = "sectxtfuzz" 1423 | version = "0.4.0" 1424 | dependencies = [ 1425 | "afl", 1426 | "sectxtlib", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "sectxtlib" 1431 | version = "0.4.0" 1432 | dependencies = [ 1433 | "chrono", 1434 | "iri-string", 1435 | "nom", 1436 | "oxilangtag", 1437 | "thiserror", 1438 | "valuable", 1439 | ] 1440 | 1441 | [[package]] 1442 | name = "security-framework" 1443 | version = "2.11.1" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1446 | dependencies = [ 1447 | "bitflags", 1448 | "core-foundation", 1449 | "core-foundation-sys", 1450 | "libc", 1451 | "security-framework-sys", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "security-framework-sys" 1456 | version = "2.15.0" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" 1459 | dependencies = [ 1460 | "core-foundation-sys", 1461 | "libc", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "semver" 1466 | version = "1.0.27" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 1469 | 1470 | [[package]] 1471 | name = "serde" 1472 | version = "1.0.228" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1475 | dependencies = [ 1476 | "serde_core", 1477 | "serde_derive", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "serde_core" 1482 | version = "1.0.228" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1485 | dependencies = [ 1486 | "serde_derive", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "serde_derive" 1491 | version = "1.0.228" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1494 | dependencies = [ 1495 | "proc-macro2", 1496 | "quote", 1497 | "syn", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "serde_json" 1502 | version = "1.0.145" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" 1505 | dependencies = [ 1506 | "itoa", 1507 | "memchr", 1508 | "ryu", 1509 | "serde", 1510 | "serde_core", 1511 | ] 1512 | 1513 | [[package]] 1514 | name = "serde_spanned" 1515 | version = "1.0.3" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" 1518 | dependencies = [ 1519 | "serde_core", 1520 | ] 1521 | 1522 | [[package]] 1523 | name = "serde_urlencoded" 1524 | version = "0.7.1" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1527 | dependencies = [ 1528 | "form_urlencoded", 1529 | "itoa", 1530 | "ryu", 1531 | "serde", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "sharded-slab" 1536 | version = "0.1.7" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1539 | dependencies = [ 1540 | "lazy_static", 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "shlex" 1545 | version = "1.3.0" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1548 | 1549 | [[package]] 1550 | name = "slab" 1551 | version = "0.4.11" 1552 | source = "registry+https://github.com/rust-lang/crates.io-index" 1553 | checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 1554 | 1555 | [[package]] 1556 | name = "smallvec" 1557 | version = "1.15.1" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1560 | 1561 | [[package]] 1562 | name = "socket2" 1563 | version = "0.6.1" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" 1566 | dependencies = [ 1567 | "libc", 1568 | "windows-sys 0.60.2", 1569 | ] 1570 | 1571 | [[package]] 1572 | name = "stable_deref_trait" 1573 | version = "1.2.1" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1576 | 1577 | [[package]] 1578 | name = "subtle" 1579 | version = "2.6.1" 1580 | source = "registry+https://github.com/rust-lang/crates.io-index" 1581 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1582 | 1583 | [[package]] 1584 | name = "syn" 1585 | version = "2.0.111" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" 1588 | dependencies = [ 1589 | "proc-macro2", 1590 | "quote", 1591 | "unicode-ident", 1592 | ] 1593 | 1594 | [[package]] 1595 | name = "sync_wrapper" 1596 | version = "1.0.2" 1597 | source = "registry+https://github.com/rust-lang/crates.io-index" 1598 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1599 | dependencies = [ 1600 | "futures-core", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "synstructure" 1605 | version = "0.13.2" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1608 | dependencies = [ 1609 | "proc-macro2", 1610 | "quote", 1611 | "syn", 1612 | ] 1613 | 1614 | [[package]] 1615 | name = "system-configuration" 1616 | version = "0.6.1" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1619 | dependencies = [ 1620 | "bitflags", 1621 | "core-foundation", 1622 | "system-configuration-sys", 1623 | ] 1624 | 1625 | [[package]] 1626 | name = "system-configuration-sys" 1627 | version = "0.6.0" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1630 | dependencies = [ 1631 | "core-foundation-sys", 1632 | "libc", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "tempfile" 1637 | version = "3.23.0" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" 1640 | dependencies = [ 1641 | "fastrand", 1642 | "getrandom 0.3.4", 1643 | "once_cell", 1644 | "rustix", 1645 | "windows-sys 0.61.2", 1646 | ] 1647 | 1648 | [[package]] 1649 | name = "thiserror" 1650 | version = "2.0.17" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" 1653 | dependencies = [ 1654 | "thiserror-impl", 1655 | ] 1656 | 1657 | [[package]] 1658 | name = "thiserror-impl" 1659 | version = "2.0.17" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" 1662 | dependencies = [ 1663 | "proc-macro2", 1664 | "quote", 1665 | "syn", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "thread_local" 1670 | version = "1.1.9" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" 1673 | dependencies = [ 1674 | "cfg-if", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "tinystr" 1679 | version = "0.8.2" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 1682 | dependencies = [ 1683 | "displaydoc", 1684 | "zerovec", 1685 | ] 1686 | 1687 | [[package]] 1688 | name = "tokio" 1689 | version = "1.48.0" 1690 | source = "registry+https://github.com/rust-lang/crates.io-index" 1691 | checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" 1692 | dependencies = [ 1693 | "bytes", 1694 | "libc", 1695 | "mio", 1696 | "pin-project-lite", 1697 | "socket2", 1698 | "tokio-macros", 1699 | "windows-sys 0.61.2", 1700 | ] 1701 | 1702 | [[package]] 1703 | name = "tokio-macros" 1704 | version = "2.6.0" 1705 | source = "registry+https://github.com/rust-lang/crates.io-index" 1706 | checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" 1707 | dependencies = [ 1708 | "proc-macro2", 1709 | "quote", 1710 | "syn", 1711 | ] 1712 | 1713 | [[package]] 1714 | name = "tokio-native-tls" 1715 | version = "0.3.1" 1716 | source = "registry+https://github.com/rust-lang/crates.io-index" 1717 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1718 | dependencies = [ 1719 | "native-tls", 1720 | "tokio", 1721 | ] 1722 | 1723 | [[package]] 1724 | name = "tokio-rustls" 1725 | version = "0.26.4" 1726 | source = "registry+https://github.com/rust-lang/crates.io-index" 1727 | checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" 1728 | dependencies = [ 1729 | "rustls", 1730 | "tokio", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "tokio-util" 1735 | version = "0.7.17" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" 1738 | dependencies = [ 1739 | "bytes", 1740 | "futures-core", 1741 | "futures-sink", 1742 | "pin-project-lite", 1743 | "tokio", 1744 | ] 1745 | 1746 | [[package]] 1747 | name = "toml" 1748 | version = "0.9.8" 1749 | source = "registry+https://github.com/rust-lang/crates.io-index" 1750 | checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" 1751 | dependencies = [ 1752 | "serde_core", 1753 | "serde_spanned", 1754 | "toml_datetime", 1755 | "toml_writer", 1756 | ] 1757 | 1758 | [[package]] 1759 | name = "toml_datetime" 1760 | version = "0.7.3" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" 1763 | dependencies = [ 1764 | "serde_core", 1765 | ] 1766 | 1767 | [[package]] 1768 | name = "toml_writer" 1769 | version = "1.0.4" 1770 | source = "registry+https://github.com/rust-lang/crates.io-index" 1771 | checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" 1772 | 1773 | [[package]] 1774 | name = "tower" 1775 | version = "0.5.2" 1776 | source = "registry+https://github.com/rust-lang/crates.io-index" 1777 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 1778 | dependencies = [ 1779 | "futures-core", 1780 | "futures-util", 1781 | "pin-project-lite", 1782 | "sync_wrapper", 1783 | "tokio", 1784 | "tower-layer", 1785 | "tower-service", 1786 | ] 1787 | 1788 | [[package]] 1789 | name = "tower-http" 1790 | version = "0.6.7" 1791 | source = "registry+https://github.com/rust-lang/crates.io-index" 1792 | checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" 1793 | dependencies = [ 1794 | "bitflags", 1795 | "bytes", 1796 | "futures-util", 1797 | "http", 1798 | "http-body", 1799 | "iri-string", 1800 | "pin-project-lite", 1801 | "tower", 1802 | "tower-layer", 1803 | "tower-service", 1804 | ] 1805 | 1806 | [[package]] 1807 | name = "tower-layer" 1808 | version = "0.3.3" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1811 | 1812 | [[package]] 1813 | name = "tower-service" 1814 | version = "0.3.3" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1817 | 1818 | [[package]] 1819 | name = "tracing" 1820 | version = "0.1.43" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" 1823 | dependencies = [ 1824 | "pin-project-lite", 1825 | "tracing-attributes", 1826 | "tracing-core", 1827 | ] 1828 | 1829 | [[package]] 1830 | name = "tracing-attributes" 1831 | version = "0.1.31" 1832 | source = "registry+https://github.com/rust-lang/crates.io-index" 1833 | checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" 1834 | dependencies = [ 1835 | "proc-macro2", 1836 | "quote", 1837 | "syn", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "tracing-core" 1842 | version = "0.1.35" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" 1845 | dependencies = [ 1846 | "once_cell", 1847 | "valuable", 1848 | ] 1849 | 1850 | [[package]] 1851 | name = "tracing-log" 1852 | version = "0.2.0" 1853 | source = "registry+https://github.com/rust-lang/crates.io-index" 1854 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 1855 | dependencies = [ 1856 | "log", 1857 | "once_cell", 1858 | "tracing-core", 1859 | ] 1860 | 1861 | [[package]] 1862 | name = "tracing-serde" 1863 | version = "0.2.0" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" 1866 | dependencies = [ 1867 | "serde", 1868 | "tracing-core", 1869 | "valuable", 1870 | "valuable-serde", 1871 | ] 1872 | 1873 | [[package]] 1874 | name = "tracing-subscriber" 1875 | version = "0.3.22" 1876 | source = "registry+https://github.com/rust-lang/crates.io-index" 1877 | checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" 1878 | dependencies = [ 1879 | "matchers", 1880 | "nu-ansi-term", 1881 | "once_cell", 1882 | "regex-automata", 1883 | "serde", 1884 | "serde_json", 1885 | "sharded-slab", 1886 | "smallvec", 1887 | "thread_local", 1888 | "tracing", 1889 | "tracing-core", 1890 | "tracing-log", 1891 | "tracing-serde", 1892 | "valuable", 1893 | "valuable-serde", 1894 | ] 1895 | 1896 | [[package]] 1897 | name = "try-lock" 1898 | version = "0.2.5" 1899 | source = "registry+https://github.com/rust-lang/crates.io-index" 1900 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1901 | 1902 | [[package]] 1903 | name = "unicode-ident" 1904 | version = "1.0.22" 1905 | source = "registry+https://github.com/rust-lang/crates.io-index" 1906 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 1907 | 1908 | [[package]] 1909 | name = "untrusted" 1910 | version = "0.9.0" 1911 | source = "registry+https://github.com/rust-lang/crates.io-index" 1912 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1913 | 1914 | [[package]] 1915 | name = "url" 1916 | version = "2.5.7" 1917 | source = "registry+https://github.com/rust-lang/crates.io-index" 1918 | checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" 1919 | dependencies = [ 1920 | "form_urlencoded", 1921 | "idna", 1922 | "percent-encoding", 1923 | "serde", 1924 | ] 1925 | 1926 | [[package]] 1927 | name = "utf8_iter" 1928 | version = "1.0.4" 1929 | source = "registry+https://github.com/rust-lang/crates.io-index" 1930 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1931 | 1932 | [[package]] 1933 | name = "utf8parse" 1934 | version = "0.2.2" 1935 | source = "registry+https://github.com/rust-lang/crates.io-index" 1936 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1937 | 1938 | [[package]] 1939 | name = "uuid" 1940 | version = "1.18.1" 1941 | source = "registry+https://github.com/rust-lang/crates.io-index" 1942 | checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" 1943 | dependencies = [ 1944 | "getrandom 0.3.4", 1945 | ] 1946 | 1947 | [[package]] 1948 | name = "valuable" 1949 | version = "0.1.1" 1950 | source = "registry+https://github.com/rust-lang/crates.io-index" 1951 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 1952 | dependencies = [ 1953 | "valuable-derive", 1954 | ] 1955 | 1956 | [[package]] 1957 | name = "valuable-derive" 1958 | version = "0.1.1" 1959 | source = "registry+https://github.com/rust-lang/crates.io-index" 1960 | checksum = "4e3a32a9bcc0f6c6ccfd5b27bcf298c58e753bcc9eeff268157a303393183a6d" 1961 | dependencies = [ 1962 | "proc-macro2", 1963 | "quote", 1964 | "syn", 1965 | ] 1966 | 1967 | [[package]] 1968 | name = "valuable-serde" 1969 | version = "0.1.1" 1970 | source = "registry+https://github.com/rust-lang/crates.io-index" 1971 | checksum = "2ee0548edecd1b907be7e67789923b7d02275b9ba4a33ebc33300e2c947a8cb1" 1972 | dependencies = [ 1973 | "serde", 1974 | "valuable", 1975 | ] 1976 | 1977 | [[package]] 1978 | name = "vcpkg" 1979 | version = "0.2.15" 1980 | source = "registry+https://github.com/rust-lang/crates.io-index" 1981 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1982 | 1983 | [[package]] 1984 | name = "want" 1985 | version = "0.3.1" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1988 | dependencies = [ 1989 | "try-lock", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "wasi" 1994 | version = "0.11.1+wasi-snapshot-preview1" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1997 | 1998 | [[package]] 1999 | name = "wasip2" 2000 | version = "1.0.1+wasi-0.2.4" 2001 | source = "registry+https://github.com/rust-lang/crates.io-index" 2002 | checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 2003 | dependencies = [ 2004 | "wit-bindgen", 2005 | ] 2006 | 2007 | [[package]] 2008 | name = "wasm-bindgen" 2009 | version = "0.2.106" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" 2012 | dependencies = [ 2013 | "cfg-if", 2014 | "once_cell", 2015 | "rustversion", 2016 | "wasm-bindgen-macro", 2017 | "wasm-bindgen-shared", 2018 | ] 2019 | 2020 | [[package]] 2021 | name = "wasm-bindgen-futures" 2022 | version = "0.4.56" 2023 | source = "registry+https://github.com/rust-lang/crates.io-index" 2024 | checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" 2025 | dependencies = [ 2026 | "cfg-if", 2027 | "js-sys", 2028 | "once_cell", 2029 | "wasm-bindgen", 2030 | "web-sys", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "wasm-bindgen-macro" 2035 | version = "0.2.106" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" 2038 | dependencies = [ 2039 | "quote", 2040 | "wasm-bindgen-macro-support", 2041 | ] 2042 | 2043 | [[package]] 2044 | name = "wasm-bindgen-macro-support" 2045 | version = "0.2.106" 2046 | source = "registry+https://github.com/rust-lang/crates.io-index" 2047 | checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" 2048 | dependencies = [ 2049 | "bumpalo", 2050 | "proc-macro2", 2051 | "quote", 2052 | "syn", 2053 | "wasm-bindgen-shared", 2054 | ] 2055 | 2056 | [[package]] 2057 | name = "wasm-bindgen-shared" 2058 | version = "0.2.106" 2059 | source = "registry+https://github.com/rust-lang/crates.io-index" 2060 | checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" 2061 | dependencies = [ 2062 | "unicode-ident", 2063 | ] 2064 | 2065 | [[package]] 2066 | name = "web-sys" 2067 | version = "0.3.83" 2068 | source = "registry+https://github.com/rust-lang/crates.io-index" 2069 | checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" 2070 | dependencies = [ 2071 | "js-sys", 2072 | "wasm-bindgen", 2073 | ] 2074 | 2075 | [[package]] 2076 | name = "windows-core" 2077 | version = "0.62.2" 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" 2079 | checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" 2080 | dependencies = [ 2081 | "windows-implement", 2082 | "windows-interface", 2083 | "windows-link", 2084 | "windows-result", 2085 | "windows-strings", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "windows-implement" 2090 | version = "0.60.2" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" 2093 | dependencies = [ 2094 | "proc-macro2", 2095 | "quote", 2096 | "syn", 2097 | ] 2098 | 2099 | [[package]] 2100 | name = "windows-interface" 2101 | version = "0.59.3" 2102 | source = "registry+https://github.com/rust-lang/crates.io-index" 2103 | checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" 2104 | dependencies = [ 2105 | "proc-macro2", 2106 | "quote", 2107 | "syn", 2108 | ] 2109 | 2110 | [[package]] 2111 | name = "windows-link" 2112 | version = "0.2.1" 2113 | source = "registry+https://github.com/rust-lang/crates.io-index" 2114 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 2115 | 2116 | [[package]] 2117 | name = "windows-registry" 2118 | version = "0.6.1" 2119 | source = "registry+https://github.com/rust-lang/crates.io-index" 2120 | checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 2121 | dependencies = [ 2122 | "windows-link", 2123 | "windows-result", 2124 | "windows-strings", 2125 | ] 2126 | 2127 | [[package]] 2128 | name = "windows-result" 2129 | version = "0.4.1" 2130 | source = "registry+https://github.com/rust-lang/crates.io-index" 2131 | checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 2132 | dependencies = [ 2133 | "windows-link", 2134 | ] 2135 | 2136 | [[package]] 2137 | name = "windows-strings" 2138 | version = "0.5.1" 2139 | source = "registry+https://github.com/rust-lang/crates.io-index" 2140 | checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 2141 | dependencies = [ 2142 | "windows-link", 2143 | ] 2144 | 2145 | [[package]] 2146 | name = "windows-sys" 2147 | version = "0.52.0" 2148 | source = "registry+https://github.com/rust-lang/crates.io-index" 2149 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2150 | dependencies = [ 2151 | "windows-targets 0.52.6", 2152 | ] 2153 | 2154 | [[package]] 2155 | name = "windows-sys" 2156 | version = "0.60.2" 2157 | source = "registry+https://github.com/rust-lang/crates.io-index" 2158 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 2159 | dependencies = [ 2160 | "windows-targets 0.53.5", 2161 | ] 2162 | 2163 | [[package]] 2164 | name = "windows-sys" 2165 | version = "0.61.2" 2166 | source = "registry+https://github.com/rust-lang/crates.io-index" 2167 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 2168 | dependencies = [ 2169 | "windows-link", 2170 | ] 2171 | 2172 | [[package]] 2173 | name = "windows-targets" 2174 | version = "0.52.6" 2175 | source = "registry+https://github.com/rust-lang/crates.io-index" 2176 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2177 | dependencies = [ 2178 | "windows_aarch64_gnullvm 0.52.6", 2179 | "windows_aarch64_msvc 0.52.6", 2180 | "windows_i686_gnu 0.52.6", 2181 | "windows_i686_gnullvm 0.52.6", 2182 | "windows_i686_msvc 0.52.6", 2183 | "windows_x86_64_gnu 0.52.6", 2184 | "windows_x86_64_gnullvm 0.52.6", 2185 | "windows_x86_64_msvc 0.52.6", 2186 | ] 2187 | 2188 | [[package]] 2189 | name = "windows-targets" 2190 | version = "0.53.5" 2191 | source = "registry+https://github.com/rust-lang/crates.io-index" 2192 | checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 2193 | dependencies = [ 2194 | "windows-link", 2195 | "windows_aarch64_gnullvm 0.53.1", 2196 | "windows_aarch64_msvc 0.53.1", 2197 | "windows_i686_gnu 0.53.1", 2198 | "windows_i686_gnullvm 0.53.1", 2199 | "windows_i686_msvc 0.53.1", 2200 | "windows_x86_64_gnu 0.53.1", 2201 | "windows_x86_64_gnullvm 0.53.1", 2202 | "windows_x86_64_msvc 0.53.1", 2203 | ] 2204 | 2205 | [[package]] 2206 | name = "windows_aarch64_gnullvm" 2207 | version = "0.52.6" 2208 | source = "registry+https://github.com/rust-lang/crates.io-index" 2209 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2210 | 2211 | [[package]] 2212 | name = "windows_aarch64_gnullvm" 2213 | version = "0.53.1" 2214 | source = "registry+https://github.com/rust-lang/crates.io-index" 2215 | checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 2216 | 2217 | [[package]] 2218 | name = "windows_aarch64_msvc" 2219 | version = "0.52.6" 2220 | source = "registry+https://github.com/rust-lang/crates.io-index" 2221 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2222 | 2223 | [[package]] 2224 | name = "windows_aarch64_msvc" 2225 | version = "0.53.1" 2226 | source = "registry+https://github.com/rust-lang/crates.io-index" 2227 | checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 2228 | 2229 | [[package]] 2230 | name = "windows_i686_gnu" 2231 | version = "0.52.6" 2232 | source = "registry+https://github.com/rust-lang/crates.io-index" 2233 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2234 | 2235 | [[package]] 2236 | name = "windows_i686_gnu" 2237 | version = "0.53.1" 2238 | source = "registry+https://github.com/rust-lang/crates.io-index" 2239 | checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 2240 | 2241 | [[package]] 2242 | name = "windows_i686_gnullvm" 2243 | version = "0.52.6" 2244 | source = "registry+https://github.com/rust-lang/crates.io-index" 2245 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2246 | 2247 | [[package]] 2248 | name = "windows_i686_gnullvm" 2249 | version = "0.53.1" 2250 | source = "registry+https://github.com/rust-lang/crates.io-index" 2251 | checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 2252 | 2253 | [[package]] 2254 | name = "windows_i686_msvc" 2255 | version = "0.52.6" 2256 | source = "registry+https://github.com/rust-lang/crates.io-index" 2257 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2258 | 2259 | [[package]] 2260 | name = "windows_i686_msvc" 2261 | version = "0.53.1" 2262 | source = "registry+https://github.com/rust-lang/crates.io-index" 2263 | checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 2264 | 2265 | [[package]] 2266 | name = "windows_x86_64_gnu" 2267 | version = "0.52.6" 2268 | source = "registry+https://github.com/rust-lang/crates.io-index" 2269 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2270 | 2271 | [[package]] 2272 | name = "windows_x86_64_gnu" 2273 | version = "0.53.1" 2274 | source = "registry+https://github.com/rust-lang/crates.io-index" 2275 | checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 2276 | 2277 | [[package]] 2278 | name = "windows_x86_64_gnullvm" 2279 | version = "0.52.6" 2280 | source = "registry+https://github.com/rust-lang/crates.io-index" 2281 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2282 | 2283 | [[package]] 2284 | name = "windows_x86_64_gnullvm" 2285 | version = "0.53.1" 2286 | source = "registry+https://github.com/rust-lang/crates.io-index" 2287 | checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 2288 | 2289 | [[package]] 2290 | name = "windows_x86_64_msvc" 2291 | version = "0.52.6" 2292 | source = "registry+https://github.com/rust-lang/crates.io-index" 2293 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2294 | 2295 | [[package]] 2296 | name = "windows_x86_64_msvc" 2297 | version = "0.53.1" 2298 | source = "registry+https://github.com/rust-lang/crates.io-index" 2299 | checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 2300 | 2301 | [[package]] 2302 | name = "wit-bindgen" 2303 | version = "0.46.0" 2304 | source = "registry+https://github.com/rust-lang/crates.io-index" 2305 | checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 2306 | 2307 | [[package]] 2308 | name = "writeable" 2309 | version = "0.6.2" 2310 | source = "registry+https://github.com/rust-lang/crates.io-index" 2311 | checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 2312 | 2313 | [[package]] 2314 | name = "xdg" 2315 | version = "3.0.0" 2316 | source = "registry+https://github.com/rust-lang/crates.io-index" 2317 | checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" 2318 | 2319 | [[package]] 2320 | name = "yoke" 2321 | version = "0.8.1" 2322 | source = "registry+https://github.com/rust-lang/crates.io-index" 2323 | checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" 2324 | dependencies = [ 2325 | "stable_deref_trait", 2326 | "yoke-derive", 2327 | "zerofrom", 2328 | ] 2329 | 2330 | [[package]] 2331 | name = "yoke-derive" 2332 | version = "0.8.1" 2333 | source = "registry+https://github.com/rust-lang/crates.io-index" 2334 | checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" 2335 | dependencies = [ 2336 | "proc-macro2", 2337 | "quote", 2338 | "syn", 2339 | "synstructure", 2340 | ] 2341 | 2342 | [[package]] 2343 | name = "zerofrom" 2344 | version = "0.1.6" 2345 | source = "registry+https://github.com/rust-lang/crates.io-index" 2346 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2347 | dependencies = [ 2348 | "zerofrom-derive", 2349 | ] 2350 | 2351 | [[package]] 2352 | name = "zerofrom-derive" 2353 | version = "0.1.6" 2354 | source = "registry+https://github.com/rust-lang/crates.io-index" 2355 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2356 | dependencies = [ 2357 | "proc-macro2", 2358 | "quote", 2359 | "syn", 2360 | "synstructure", 2361 | ] 2362 | 2363 | [[package]] 2364 | name = "zeroize" 2365 | version = "1.8.2" 2366 | source = "registry+https://github.com/rust-lang/crates.io-index" 2367 | checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 2368 | 2369 | [[package]] 2370 | name = "zerotrie" 2371 | version = "0.2.3" 2372 | source = "registry+https://github.com/rust-lang/crates.io-index" 2373 | checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" 2374 | dependencies = [ 2375 | "displaydoc", 2376 | "yoke", 2377 | "zerofrom", 2378 | ] 2379 | 2380 | [[package]] 2381 | name = "zerovec" 2382 | version = "0.11.5" 2383 | source = "registry+https://github.com/rust-lang/crates.io-index" 2384 | checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 2385 | dependencies = [ 2386 | "yoke", 2387 | "zerofrom", 2388 | "zerovec-derive", 2389 | ] 2390 | 2391 | [[package]] 2392 | name = "zerovec-derive" 2393 | version = "0.11.2" 2394 | source = "registry+https://github.com/rust-lang/crates.io-index" 2395 | checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" 2396 | dependencies = [ 2397 | "proc-macro2", 2398 | "quote", 2399 | "syn", 2400 | ] 2401 | --------------------------------------------------------------------------------