hackerone_api/lib.rs
1//! # hackerone-api
2//!
3//! Unofficial, dependency-light Rust client for the [HackerOne API][api] (v1).
4//!
5//! Built for the boring, reliable half of bug-bounty tooling: sign in, browse
6//! your programs and their scopes, read your reports, **submit** a report,
7//! search hacktivity, and read your balance and earnings — with HTTP Basic
8//! auth and no async runtime.
9//!
10//! ## Hacker surface
11//!
12//! Report *submission* is a **hacker** operation. It lives under
13//! `/v1/hackers/…`, not the customer `/v1/reports` surface. These endpoints
14//! work with a researcher's API token:
15//!
16//! | Method | Endpoint |
17//! |---|---|
18//! | [`Client::create_report`] | `POST /v1/hackers/reports` |
19//! | [`Client::my_reports`] | `GET /v1/hackers/me/reports` |
20//! | [`Client::my_report`] | `GET /v1/hackers/reports/{id}` |
21//! | [`Client::hacktivity`] | `GET /v1/hackers/hacktivity` |
22//! | [`Client::balance`] | `GET /v1/hackers/payments/balance` |
23//! | [`Client::earnings`] | `GET /v1/hackers/payments/earnings` |
24//!
25//! ## Customer surface
26//!
27//! [`Client::me`], [`Client::programs`], [`Client::program`],
28//! [`Client::structured_scopes`], [`Client::reports`], [`Client::report`],
29//! [`Client::add_comment`], [`Client::change_state`] and
30//! [`Client::weaknesses`] are the **customer/program** API. A hacker-only API
31//! token receives `401` on those routes (they require program access), even
32//! though the token is valid.
33//!
34//! ## Submit a report
35//!
36//! ```no_run
37//! use hackerone_api::{Client, CreateHackerReport, SeverityRating};
38//!
39//! fn main() -> Result<(), hackerone_api::Error> {
40//! let client = Client::new("api-identifier", "api-token");
41//!
42//! let report = CreateHackerReport::new("sec", "Stored XSS in the profile page")
43//! .vulnerability_information("## Steps\n1. …")
44//! .impact("Session theft for any user who views the profile.")
45//! .severity(SeverityRating::High)
46//! .weakness_id(1337)
47//! .structured_scope_id(57);
48//!
49//! let created = client.create_report(&report)?;
50//! println!("filed: {} [{}]", created.title.unwrap_or_default(), created.state.unwrap_or_default());
51//! Ok(())
52//! }
53//! ```
54//!
55//! The created report's numeric id is returned on the response envelope's
56//! `data.id`; [`Client::create_report`] returns the report attributes
57//! ([`Report`]), matching [`Client::report`]. To read ids for existing
58//! reports, use [`Client::my_reports`] and [`Page::ids`].
59//!
60//! ## Auth
61//!
62//! The API uses HTTP Basic auth: the *username* is your API token
63//! **identifier** and the *password* is the token **value**. Create one in
64//! your HackerOne account settings. The examples read them from the
65//! `HACKERONE_API_IDENTIFIER` / `HACKERONE_API_TOKEN` environment variables.
66//!
67//! ## Design
68//!
69//! - **Blocking, no async runtime.** [`ureq`] under the hood.
70//! - **Injectable transport.** The client is generic over [`Transport`], so
71//! tests use a mock and embedders can swap the HTTP stack.
72//! - **Forward-compatible types.** Domain structs keep the documented fields
73//! and stash unknown ones in a flattened `extra` map.
74//!
75//! ## Disclaimer
76//!
77//! This crate is unofficial and not affiliated with or endorsed by
78//! HackerOne. "HackerOne" is a trademark of its owner; the name is used only
79//! to describe what the library talks to.
80//!
81//! [api]: https://api.hackerone.com/
82
83#![forbid(unsafe_code)]
84#![warn(missing_docs)]
85
86mod client;
87mod error;
88mod transport;
89mod types;
90
91pub use client::{Client, DEFAULT_BASE_URL};
92pub use error::{ApiError, Error, Result};
93pub use transport::{Method, Request, Response, Transport, UreqTransport};
94pub use types::{
95 Balance, CollectionDoc, CreateHackerReport, DataDoc, Earning, Hacktivity, HacktivityQuery,
96 Links, Meta, Page, PageQuery, Program, Report, ReportQuery, ReportState, Resource, Severity,
97 SeverityRating, SingleDoc, StructuredScope, User, Weakness,
98};