mirror of
https://git.asonix.dog/asonix/relay.git
synced 2024-11-25 11:01:11 +00:00
Make admin API & client work
This commit is contained in:
parent
fe844a807f
commit
ebdc739c84
12 changed files with 145 additions and 48 deletions
1
.env
1
.env
|
@ -1,4 +1,5 @@
|
||||||
HOSTNAME=localhost:8079
|
HOSTNAME=localhost:8079
|
||||||
PORT=8079
|
PORT=8079
|
||||||
RESTRICTED_MODE=true
|
RESTRICTED_MODE=true
|
||||||
|
API_TOKEN=somesecretpassword
|
||||||
# OPENTELEMETRY_URL=http://localhost:4317
|
# OPENTELEMETRY_URL=http://localhost:4317
|
||||||
|
|
|
@ -36,6 +36,9 @@ To simply run the server, the command is as follows
|
||||||
$ ./relay
|
$ ./relay
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Administration
|
||||||
|
> **NOTE:** The server _must be running_ in order to update the lists with the following commands
|
||||||
|
|
||||||
To learn about any other tasks, the `--help` flag can be passed
|
To learn about any other tasks, the `--help` flag can be passed
|
||||||
```bash
|
```bash
|
||||||
An activitypub relay
|
An activitypub relay
|
||||||
|
@ -91,6 +94,7 @@ PRETTY_LOG=false
|
||||||
PUBLISH_BLOCKS=true
|
PUBLISH_BLOCKS=true
|
||||||
SLED_PATH=./sled/db-0.34
|
SLED_PATH=./sled/db-0.34
|
||||||
RUST_LOG=warn
|
RUST_LOG=warn
|
||||||
|
API_TOKEN=somepasswordishtoken
|
||||||
OPENTELEMETRY_URL=localhost:4317
|
OPENTELEMETRY_URL=localhost:4317
|
||||||
TELEGRAM_TOKEN=secret
|
TELEGRAM_TOKEN=secret
|
||||||
TELEGRAM_ADMIN_HANDLE=your_handle
|
TELEGRAM_ADMIN_HANDLE=your_handle
|
||||||
|
@ -119,6 +123,8 @@ Where to store the on-disk database of connected servers. This defaults to `./sl
|
||||||
The log level to print. Available levels are `ERROR`, `WARN`, `INFO`, `DEBUG`, and `TRACE`. You can also specify module paths to enable some logs but not others, such as `RUST_LOG=warn,tracing_actix_web=info,relay=info`
|
The log level to print. Available levels are `ERROR`, `WARN`, `INFO`, `DEBUG`, and `TRACE`. You can also specify module paths to enable some logs but not others, such as `RUST_LOG=warn,tracing_actix_web=info,relay=info`
|
||||||
##### `SOURCE_REPO`
|
##### `SOURCE_REPO`
|
||||||
The URL to the source code for the relay. This defaults to `https://git.asonix.dog/asonix/relay`, but should be changed if you're running a fork hosted elsewhere.
|
The URL to the source code for the relay. This defaults to `https://git.asonix.dog/asonix/relay`, but should be changed if you're running a fork hosted elsewhere.
|
||||||
|
##### `API_TOKEN`
|
||||||
|
The Secret token used to access the admin APIs. This must be set for the commandline to function
|
||||||
##### `OPENTELEMETRY_URL`
|
##### `OPENTELEMETRY_URL`
|
||||||
A URL for exporting opentelemetry spans. This is mostly useful for debugging. There is no default, since most people probably don't run an opentelemetry collector.
|
A URL for exporting opentelemetry spans. This is mostly useful for debugging. There is no default, since most people probably don't run an opentelemetry collector.
|
||||||
##### `TELEGRAM_TOKEN`
|
##### `TELEGRAM_TOKEN`
|
||||||
|
|
|
@ -10,15 +10,15 @@ pub(crate) struct Domains {
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
pub(crate) struct AllowedDomains {
|
pub(crate) struct AllowedDomains {
|
||||||
allowed_domains: Vec<String>,
|
pub(crate) allowed_domains: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
pub(crate) struct BlockedDomains {
|
pub(crate) struct BlockedDomains {
|
||||||
blocked_domains: Vec<String>,
|
pub(crate) blocked_domains: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
pub(crate) struct ConnectedActors {
|
pub(crate) struct ConnectedActors {
|
||||||
connected_actors: Vec<IriString>,
|
pub(crate) connected_actors: Vec<IriString>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,14 @@ pub(crate) async fn allow(
|
||||||
post_domains(client, config, domains, AdminUrlKind::Allow).await
|
post_domains(client, config, domains, AdminUrlKind::Allow).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn disallow(
|
||||||
|
client: &Client,
|
||||||
|
config: &Config,
|
||||||
|
domains: Vec<String>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
post_domains(client, config, domains, AdminUrlKind::Disallow).await
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn block(
|
pub(crate) async fn block(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
@ -22,6 +30,14 @@ pub(crate) async fn block(
|
||||||
post_domains(client, config, domains, AdminUrlKind::Block).await
|
post_domains(client, config, domains, AdminUrlKind::Block).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn unblock(
|
||||||
|
client: &Client,
|
||||||
|
config: &Config,
|
||||||
|
domains: Vec<String>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
post_domains(client, config, domains, AdminUrlKind::Unblock).await
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn allowed(client: &Client, config: &Config) -> Result<AllowedDomains, Error> {
|
pub(crate) async fn allowed(client: &Client, config: &Config) -> Result<AllowedDomains, Error> {
|
||||||
get_results(client, config, AdminUrlKind::Allowed).await
|
get_results(client, config, AdminUrlKind::Allowed).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,15 @@ pub(crate) async fn allow(
|
||||||
Ok(HttpResponse::NoContent().finish())
|
Ok(HttpResponse::NoContent().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn disallow(
|
||||||
|
admin: Admin,
|
||||||
|
Json(Domains { domains }): Json<Domains>,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
admin.db_ref().remove_allows(domains).await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::NoContent().finish())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn block(
|
pub(crate) async fn block(
|
||||||
admin: Admin,
|
admin: Admin,
|
||||||
Json(Domains { domains }): Json<Domains>,
|
Json(Domains { domains }): Json<Domains>,
|
||||||
|
@ -23,20 +32,29 @@ pub(crate) async fn block(
|
||||||
Ok(HttpResponse::NoContent().finish())
|
Ok(HttpResponse::NoContent().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn allowed(admin: Admin) -> Result<HttpResponse, Error> {
|
pub(crate) async fn unblock(
|
||||||
let allowed_domains = admin.db_ref().allowed_domains().await?;
|
admin: Admin,
|
||||||
|
Json(Domains { domains }): Json<Domains>,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
admin.db_ref().remove_blocks(domains).await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(AllowedDomains { allowed_domains }))
|
Ok(HttpResponse::NoContent().finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn blocked(admin: Admin) -> Result<HttpResponse, Error> {
|
pub(crate) async fn allowed(admin: Admin) -> Result<Json<AllowedDomains>, Error> {
|
||||||
|
let allowed_domains = admin.db_ref().allows().await?;
|
||||||
|
|
||||||
|
Ok(Json(AllowedDomains { allowed_domains }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn blocked(admin: Admin) -> Result<Json<BlockedDomains>, Error> {
|
||||||
let blocked_domains = admin.db_ref().blocks().await?;
|
let blocked_domains = admin.db_ref().blocks().await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(BlockedDomains { blocked_domains }))
|
Ok(Json(BlockedDomains { blocked_domains }))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn connected(admin: Admin) -> Result<HttpResponse, Error> {
|
pub(crate) async fn connected(admin: Admin) -> Result<Json<ConnectedActors>, Error> {
|
||||||
let connected_actors = admin.db_ref().connected_ids().await?;
|
let connected_actors = admin.db_ref().connected_ids().await?;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(ConnectedActors { connected_actors }))
|
Ok(Json(ConnectedActors { connected_actors }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,10 @@ pub(crate) struct Args {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
|
pub(crate) fn any(&self) -> bool {
|
||||||
|
!self.blocks.is_empty() || !self.allowed.is_empty() || self.list
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self::parse()
|
Self::parse()
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,9 @@ pub enum UrlKind {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AdminUrlKind {
|
pub enum AdminUrlKind {
|
||||||
Allow,
|
Allow,
|
||||||
|
Disallow,
|
||||||
Block,
|
Block,
|
||||||
|
Unblock,
|
||||||
Allowed,
|
Allowed,
|
||||||
Blocked,
|
Blocked,
|
||||||
Connected,
|
Connected,
|
||||||
|
@ -324,8 +326,12 @@ impl Config {
|
||||||
let iri = match kind {
|
let iri = match kind {
|
||||||
AdminUrlKind::Allow => FixedBaseResolver::new(self.base_uri.as_ref())
|
AdminUrlKind::Allow => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||||
.try_resolve(IriRelativeStr::new("api/v1/admin/allow")?.as_ref())?,
|
.try_resolve(IriRelativeStr::new("api/v1/admin/allow")?.as_ref())?,
|
||||||
|
AdminUrlKind::Disallow => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||||
|
.try_resolve(IriRelativeStr::new("api/v1/admin/disallow")?.as_ref())?,
|
||||||
AdminUrlKind::Block => FixedBaseResolver::new(self.base_uri.as_ref())
|
AdminUrlKind::Block => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||||
.try_resolve(IriRelativeStr::new("api/v1/admin/block")?.as_ref())?,
|
.try_resolve(IriRelativeStr::new("api/v1/admin/block")?.as_ref())?,
|
||||||
|
AdminUrlKind::Unblock => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||||
|
.try_resolve(IriRelativeStr::new("api/v1/admin/unblock")?.as_ref())?,
|
||||||
AdminUrlKind::Allowed => FixedBaseResolver::new(self.base_uri.as_ref())
|
AdminUrlKind::Allowed => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||||
.try_resolve(IriRelativeStr::new("api/v1/admin/allowed")?.as_ref())?,
|
.try_resolve(IriRelativeStr::new("api/v1/admin/allowed")?.as_ref())?,
|
||||||
AdminUrlKind::Blocked => FixedBaseResolver::new(self.base_uri.as_ref())
|
AdminUrlKind::Blocked => FixedBaseResolver::new(self.base_uri.as_ref())
|
||||||
|
|
|
@ -281,10 +281,6 @@ impl Db {
|
||||||
self.unblock(|inner| Ok(inner.connected().collect())).await
|
self.unblock(|inner| Ok(inner.connected().collect())).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn allowed_domains(&self) -> Result<Vec<String>, Error> {
|
|
||||||
self.unblock(|inner| Ok(inner.allowed().collect())).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn save_info(&self, actor_id: IriString, info: Info) -> Result<(), Error> {
|
pub(crate) async fn save_info(&self, actor_id: IriString, info: Info) -> Result<(), Error> {
|
||||||
self.unblock(move |inner| {
|
self.unblock(move |inner| {
|
||||||
let vec = serde_json::to_vec(&info)?;
|
let vec = serde_json::to_vec(&info)?;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::Payload,
|
dev::Payload,
|
||||||
error::ParseError,
|
error::{BlockingError, ParseError},
|
||||||
http::{
|
http::{
|
||||||
header::{from_one_raw_str, Header, HeaderName, HeaderValue, TryIntoHeaderValue},
|
header::{from_one_raw_str, Header, HeaderName, HeaderValue, TryIntoHeaderValue},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
|
@ -9,12 +9,9 @@ use actix_web::{
|
||||||
FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
|
FromRequest, HttpMessage, HttpRequest, HttpResponse, ResponseError,
|
||||||
};
|
};
|
||||||
use bcrypt::{BcryptError, DEFAULT_COST};
|
use bcrypt::{BcryptError, DEFAULT_COST};
|
||||||
|
use futures_util::future::LocalBoxFuture;
|
||||||
use http_signature_normalization_actix::prelude::InvalidHeaderValue;
|
use http_signature_normalization_actix::prelude::InvalidHeaderValue;
|
||||||
use std::{
|
use std::{convert::Infallible, str::FromStr};
|
||||||
convert::Infallible,
|
|
||||||
future::{ready, Ready},
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
use tracing_error::SpanTrace;
|
use tracing_error::SpanTrace;
|
||||||
|
|
||||||
use crate::db::Db;
|
use crate::db::Db;
|
||||||
|
@ -32,7 +29,7 @@ impl AdminConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify(&self, token: XApiToken) -> Result<bool, Error> {
|
fn verify(&self, token: XApiToken) -> Result<bool, Error> {
|
||||||
Ok(bcrypt::verify(&self.hashed_api_token, &token.0).map_err(Error::bcrypt_verify)?)
|
Ok(bcrypt::verify(&token.0, &self.hashed_api_token).map_err(Error::bcrypt_verify)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,18 +38,34 @@ pub(crate) struct Admin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Admin {
|
impl Admin {
|
||||||
#[tracing::instrument(level = "debug", skip(req))]
|
fn prepare_verify(
|
||||||
fn verify(req: &HttpRequest) -> Result<Self, Error> {
|
req: &HttpRequest,
|
||||||
|
) -> Result<(Data<Db>, Data<AdminConfig>, XApiToken), Error> {
|
||||||
let hashed_api_token = req
|
let hashed_api_token = req
|
||||||
.app_data::<Data<AdminConfig>>()
|
.app_data::<Data<AdminConfig>>()
|
||||||
.ok_or_else(Error::missing_config)?;
|
.ok_or_else(Error::missing_config)?
|
||||||
|
.clone();
|
||||||
|
|
||||||
let x_api_token = XApiToken::parse(req).map_err(Error::parse_header)?;
|
let x_api_token = XApiToken::parse(req).map_err(Error::parse_header)?;
|
||||||
|
|
||||||
if hashed_api_token.verify(x_api_token)? {
|
let db = req
|
||||||
let db = req.app_data::<Data<Db>>().ok_or_else(Error::missing_db)?;
|
.app_data::<Data<Db>>()
|
||||||
|
.ok_or_else(Error::missing_db)?
|
||||||
|
.clone();
|
||||||
|
|
||||||
return Ok(Self { db: db.clone() });
|
Ok((db, hashed_api_token, x_api_token))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip_all)]
|
||||||
|
async fn verify(
|
||||||
|
hashed_api_token: Data<AdminConfig>,
|
||||||
|
x_api_token: XApiToken,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if actix_web::web::block(move || hashed_api_token.verify(x_api_token))
|
||||||
|
.await
|
||||||
|
.map_err(Error::canceled)??
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Error::invalid())
|
Err(Error::invalid())
|
||||||
|
@ -113,6 +126,13 @@ impl Error {
|
||||||
kind: ErrorKind::ParseHeader(e),
|
kind: ErrorKind::ParseHeader(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn canceled(_: BlockingError) -> Self {
|
||||||
|
Error {
|
||||||
|
context: SpanTrace::capture(),
|
||||||
|
kind: ErrorKind::Canceled,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
@ -126,6 +146,9 @@ enum ErrorKind {
|
||||||
#[error("Missing Db")]
|
#[error("Missing Db")]
|
||||||
MissingDb,
|
MissingDb,
|
||||||
|
|
||||||
|
#[error("Panic in verify")]
|
||||||
|
Canceled,
|
||||||
|
|
||||||
#[error("Verifying")]
|
#[error("Verifying")]
|
||||||
BCryptVerify(#[source] BcryptError),
|
BCryptVerify(#[source] BcryptError),
|
||||||
|
|
||||||
|
@ -152,10 +175,15 @@ impl ResponseError for Error {
|
||||||
|
|
||||||
impl FromRequest for Admin {
|
impl FromRequest for Admin {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Ready<Result<Self, Self::Error>>;
|
type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
|
||||||
|
|
||||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||||
ready(Admin::verify(req))
|
let res = Self::prepare_verify(req);
|
||||||
|
Box::pin(async move {
|
||||||
|
let (db, c, t) = res?;
|
||||||
|
Self::verify(c, t).await?;
|
||||||
|
Ok(Admin { db })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
56
src/main.rs
56
src/main.rs
|
@ -99,30 +99,50 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
init_subscriber(Config::software_name(), config.opentelemetry_url())?;
|
init_subscriber(Config::software_name(), config.opentelemetry_url())?;
|
||||||
|
|
||||||
let db = Db::build(&config)?;
|
|
||||||
|
|
||||||
let args = Args::new();
|
let args = Args::new();
|
||||||
|
|
||||||
if args.list() {
|
if args.any() {
|
||||||
for domain in db.blocks().await? {
|
let client = requests::build_client(&config.user_agent());
|
||||||
println!("block {}", domain);
|
|
||||||
|
if !args.blocks().is_empty() || !args.allowed().is_empty() {
|
||||||
|
if args.undo() {
|
||||||
|
admin::client::unblock(&client, &config, args.blocks().to_vec()).await?;
|
||||||
|
admin::client::disallow(&client, &config, args.allowed().to_vec()).await?;
|
||||||
|
} else {
|
||||||
|
admin::client::block(&client, &config, args.blocks().to_vec()).await?;
|
||||||
|
admin::client::allow(&client, &config, args.allowed().to_vec()).await?;
|
||||||
|
}
|
||||||
|
println!("Updated lists");
|
||||||
}
|
}
|
||||||
for domain in db.allows().await? {
|
|
||||||
println!("allow {}", domain);
|
if args.list() {
|
||||||
|
let (blocked, allowed, connected) = tokio::try_join!(
|
||||||
|
admin::client::blocked(&client, &config),
|
||||||
|
admin::client::allowed(&client, &config),
|
||||||
|
admin::client::connected(&client, &config)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut report = String::from("Report:\n");
|
||||||
|
if !allowed.allowed_domains.is_empty() {
|
||||||
|
report += "\nAllowed\n\t";
|
||||||
|
report += &allowed.allowed_domains.join("\n\t");
|
||||||
|
}
|
||||||
|
if !blocked.blocked_domains.is_empty() {
|
||||||
|
report += "\n\nBlocked\n\t";
|
||||||
|
report += &blocked.blocked_domains.join("\n\t");
|
||||||
|
}
|
||||||
|
if !connected.connected_actors.is_empty() {
|
||||||
|
report += "\n\nConnected\n\t";
|
||||||
|
report += &connected.connected_actors.join("\n\t");
|
||||||
|
}
|
||||||
|
report += "\n";
|
||||||
|
println!("{report}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !args.blocks().is_empty() || !args.allowed().is_empty() {
|
let db = Db::build(&config)?;
|
||||||
if args.undo() {
|
|
||||||
db.remove_blocks(args.blocks().to_vec()).await?;
|
|
||||||
db.remove_allows(args.allowed().to_vec()).await?;
|
|
||||||
} else {
|
|
||||||
db.add_blocks(args.blocks().to_vec()).await?;
|
|
||||||
db.add_allows(args.allowed().to_vec()).await?;
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let media = MediaCache::new(db.clone());
|
let media = MediaCache::new(db.clone());
|
||||||
let state = State::build(db.clone()).await?;
|
let state = State::build(db.clone()).await?;
|
||||||
|
@ -178,7 +198,9 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
web::scope("/api/v1").service(
|
web::scope("/api/v1").service(
|
||||||
web::scope("/admin")
|
web::scope("/admin")
|
||||||
.route("/allow", web::post().to(admin::routes::allow))
|
.route("/allow", web::post().to(admin::routes::allow))
|
||||||
|
.route("/disallow", web::post().to(admin::routes::disallow))
|
||||||
.route("/block", web::post().to(admin::routes::block))
|
.route("/block", web::post().to(admin::routes::block))
|
||||||
|
.route("/unblock", web::post().to(admin::routes::unblock))
|
||||||
.route("/allowed", web::get().to(admin::routes::allowed))
|
.route("/allowed", web::get().to(admin::routes::allowed))
|
||||||
.route("/blocked", web::get().to(admin::routes::blocked))
|
.route("/blocked", web::get().to(admin::routes::blocked))
|
||||||
.route("/connected", web::get().to(admin::routes::connected)),
|
.route("/connected", web::get().to(admin::routes::connected)),
|
||||||
|
|
|
@ -160,7 +160,7 @@ impl std::fmt::Debug for Requests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_client(user_agent: &str) -> Client {
|
pub(crate) fn build_client(user_agent: &str) -> Client {
|
||||||
Client::builder()
|
Client::builder()
|
||||||
.wrap(Tracing)
|
.wrap(Tracing)
|
||||||
.add_default_header(("User-Agent", user_agent.to_string()))
|
.add_default_header(("User-Agent", user_agent.to_string()))
|
||||||
|
|
|
@ -105,7 +105,7 @@ async fn answer(bot: Bot, msg: Message, cmd: Command, db: Db) -> ResponseResult<
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Command::ListAllowed => {
|
Command::ListAllowed => {
|
||||||
if let Ok(allowed) = db.allowed_domains().await {
|
if let Ok(allowed) = db.allows().await {
|
||||||
bot.send_message(msg.chat.id, allowed.join("\n")).await?;
|
bot.send_message(msg.chat.id, allowed.join("\n")).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue