Compare commits
9 Commits
master
...
feat-nginx
Author | SHA1 | Date |
---|---|---|
Aravinth Manivannan | ca6bae8463 | |
Aravinth Manivannan | ad0c7ae94d | |
Aravinth Manivannan | e7068cfc7c | |
Aravinth Manivannan | 62278abede | |
Aravinth Manivannan | 1e5a3d57b5 | |
Aravinth Manivannan | e9237d3586 | |
Aravinth Manivannan | efdff0bc26 | |
Aravinth Manivannan | 2401d40047 | |
Aravinth Manivannan | bfaf077c02 |
|
@ -1,10 +1,16 @@
|
|||
pipeline:
|
||||
backend:
|
||||
image: rust
|
||||
# environment:
|
||||
# - DATABASE_URL=postgres://postgres:password@database:5432/postgres
|
||||
commands:
|
||||
# - make migrate
|
||||
- apt update
|
||||
- apt-get install -y --no-install-recommends nginx sudo
|
||||
- mkdir -p /etc/librepages/nginx/sites-available
|
||||
- mkdir -p /etc/librepages/nginx/sites-enabled/
|
||||
- sed -i "s%include \/etc\/nginx\/sites-enabled%include \/etc\/librepages\/nginx\/sites-enabled%" /etc/nginx/nginx.conf
|
||||
- mkdir /var/www/website/ && echo "Hello Librepages" > /var/www/website/index.html
|
||||
# nginx_le_bind runs this command.
|
||||
# Testing beforehand to ensure it is setup properly
|
||||
- sudo nginx -t
|
||||
- make
|
||||
- make test
|
||||
- make release
|
||||
|
@ -21,15 +27,12 @@ pipeline:
|
|||
|
||||
publish:
|
||||
image: plugins/docker
|
||||
when:
|
||||
event: push
|
||||
branch: master
|
||||
settings:
|
||||
username: realaravinth
|
||||
password:
|
||||
from_secret: DOCKER_TOKEN
|
||||
repo: realaravinth/librepages-conductor
|
||||
tags: latest
|
||||
|
||||
#services:
|
||||
# database:
|
||||
# image: postgres
|
||||
# environment:
|
||||
# - POSTGRES_PASSWORD=password
|
||||
|
|
|
@ -208,18 +208,6 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-web-prom"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9df3127d20a5d01c9fc9aceb969a38d31a6767e1b48a54d55a8f56c769a84923"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"prometheus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
|
@ -427,7 +415,6 @@ dependencies = [
|
|||
"actix-web",
|
||||
"actix-web-codegen-const-routes",
|
||||
"actix-web-httpauth",
|
||||
"actix-web-prom",
|
||||
"base64",
|
||||
"clap",
|
||||
"config",
|
||||
|
@ -1421,20 +1408,6 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"parking_lot 0.12.1",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
|
|
|
@ -12,7 +12,6 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
actix-web = "4"
|
||||
actix-web-prom = "0.6.0"
|
||||
futures-util = { version = "0.3.17", default-features = false, features = ["std"] }
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.17"
|
||||
|
|
|
@ -3,7 +3,8 @@ source_code = "https://git.batsense.net/librepages/conductor"
|
|||
conductor = "dummy"
|
||||
|
||||
[creds]
|
||||
token="longrandomlygeneratedpassword"
|
||||
username = "librepages_api"
|
||||
password="longrandomlygeneratedpassword"
|
||||
|
||||
[server]
|
||||
# Please set a unique value, your mCaptcha instance's security depends on this being
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
[Unit]
|
||||
Description=LibrePages Conductor: Easiest way to deploy websites. Conductor component
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=/usr/bin/conductor serve
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
SuccessExitStatus=3 4
|
||||
RestartForceExitStatus=3 4
|
||||
SystemCallArchitectures=native
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=true
|
||||
Environment="RUST_LOG=info"
|
||||
|
||||
[Unit]
|
||||
Wants=network-online.target
|
||||
Wants=network-online.target
|
||||
Requires=postgresql.service
|
||||
After=syslog.target
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -30,6 +30,7 @@ pub enum EventType {
|
|||
},
|
||||
|
||||
Config {
|
||||
hostname: String,
|
||||
data: LibConfig,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
target/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "nginx_bind_le"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
include = ["/templates"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features=["derive"]}
|
||||
serde_json = { version ="1", features = ["raw_value"]}
|
||||
async-trait = "0.1.57"
|
||||
tokio = { version = "1.23.0", features = ["process", "fs", "io-util"] }
|
||||
tera = "1.17.1"
|
||||
rust-embed = "6.4.2"
|
||||
lazy_static = "1.4.0"
|
||||
libconfig = { version = "0.1.0", git = "https://git.batsense.net/librepages/libconfig" }
|
||||
|
||||
[dependencies.libconductor]
|
||||
path = "../libconductor"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.23.0", features = ["rt-multi-thread", "macros", "rt"] }
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use async_trait::async_trait;
|
||||
use tokio::process::Command;
|
||||
|
||||
use libconductor::*;
|
||||
|
||||
mod nginx;
|
||||
mod templates;
|
||||
|
||||
use nginx::Nginx;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct NginxBindLEConductor;
|
||||
|
||||
const CONDUCTOR_NAME: &str = "NGINX_BIND_LE_CONDUCTOR";
|
||||
|
||||
#[async_trait]
|
||||
impl Conductor for NginxBindLEConductor {
|
||||
async fn process(&self, event: EventType) {
|
||||
match event {
|
||||
EventType::NewSite {
|
||||
hostname,
|
||||
path,
|
||||
branch: _branch,
|
||||
} => {
|
||||
Nginx::new_site(&hostname, &path, None).await.unwrap();
|
||||
}
|
||||
EventType::Config { hostname, data } => {
|
||||
unimplemented!();
|
||||
// Nginx::new_site(&hostname, &path, Some(data)).await.unwrap();
|
||||
}
|
||||
EventType::DeleteSite { hostname } => {
|
||||
Nginx::rm_site(&hostname).await.unwrap();
|
||||
}
|
||||
};
|
||||
}
|
||||
fn name(&self) -> &'static str {
|
||||
CONDUCTOR_NAME
|
||||
}
|
||||
|
||||
async fn health(&self) -> bool {
|
||||
nginx::Nginx::env_exists() && nginx::Nginx::status().await
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::process::Stdio;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn all_good() {
|
||||
const HOSTNAME: &str = "lab.batsense.net";
|
||||
let c = NginxBindLEConductor {};
|
||||
assert_eq!(c.name(), CONDUCTOR_NAME);
|
||||
assert!(c.health().await);
|
||||
if Nginx::site_exists(HOSTNAME) {
|
||||
c.process(EventType::DeleteSite {
|
||||
hostname: HOSTNAME.into(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
c.process(EventType::NewSite {
|
||||
hostname: HOSTNAME.into(),
|
||||
branch: "librepages".into(),
|
||||
path: "/var/www/website/".into(),
|
||||
})
|
||||
.await;
|
||||
|
||||
let out = tokio::process::Command::new("sudo")
|
||||
.arg("nginx")
|
||||
.arg("-T")
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let expected = format!("server_name {HOSTNAME}");
|
||||
let out = String::from_utf8(out.stdout).unwrap();
|
||||
assert!(out.contains(&expected));
|
||||
c.process(EventType::DeleteSite {
|
||||
hostname: HOSTNAME.into(),
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use tera::*;
|
||||
use tokio::fs;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::templates::*;
|
||||
|
||||
pub struct Nginx;
|
||||
|
||||
impl Nginx {
|
||||
pub async fn reload() -> MyResult<()> {
|
||||
Command::new("sudo")
|
||||
.arg("nginx")
|
||||
.arg("-s")
|
||||
.arg("reload")
|
||||
.spawn()?
|
||||
.wait()
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
pub async fn status() -> bool {
|
||||
async fn run_async_cmd(cmd: &mut Command) -> bool {
|
||||
if let Ok(mut child) = cmd.spawn() {
|
||||
if let Ok(res) = child.wait().await {
|
||||
return res.success();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
run_async_cmd(Command::new("sudo").arg("nginx").arg("-t")).await
|
||||
}
|
||||
|
||||
pub async fn new_site(
|
||||
hostname: &str,
|
||||
path: &str,
|
||||
config: Option<libconfig::Config>,
|
||||
) -> MyResult<()> {
|
||||
let config = CreateSite::new(hostname, path, config);
|
||||
let contents = config.render();
|
||||
let staging = Self::get_staging(hostname);
|
||||
let prod = Self::get_prod(hostname);
|
||||
|
||||
let mut file = fs::File::create(&staging).await?;
|
||||
file.write_all(contents.as_bytes()).await?;
|
||||
file.sync_all().await?;
|
||||
fs::symlink(&staging, &prod).await?;
|
||||
Self::reload().await
|
||||
}
|
||||
|
||||
fn get_staging(hostname: &str) -> PathBuf {
|
||||
Path::new(NGINX_STAGING_CONFIG_PATH).join(hostname)
|
||||
}
|
||||
fn get_prod(hostname: &str) -> PathBuf {
|
||||
Path::new(NGINX_PRODUCTION_CONFIG_PATH).join(hostname)
|
||||
}
|
||||
|
||||
pub fn site_exists(hostname: &str) -> bool {
|
||||
Self::get_prod(hostname).exists()
|
||||
}
|
||||
|
||||
pub async fn rm_site(hostname: &str) -> MyResult<()> {
|
||||
let staging = Self::get_staging(hostname);
|
||||
let prod = Self::get_prod(hostname);
|
||||
|
||||
fs::remove_file(&prod).await?;
|
||||
fs::remove_file(&staging).await?;
|
||||
Self::reload().await
|
||||
}
|
||||
|
||||
pub fn env_exists() -> bool {
|
||||
let prod = Path::new(NGINX_PRODUCTION_CONFIG_PATH);
|
||||
let staging = Path::new(NGINX_STAGING_CONFIG_PATH);
|
||||
prod.exists() && prod.is_dir() && staging.exists() && staging.is_dir()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateSite {
|
||||
ctx: RefCell<Context>,
|
||||
}
|
||||
|
||||
pub const CREATE_SITE: TemplateFile = TemplateFile::new("create_site", "nginx/create-site.j2");
|
||||
pub const CREATE_SITE_FRAGMENT: TemplateFile =
|
||||
TemplateFile::new("new_site_frag", "nginx/_new_site.fragement.j2");
|
||||
|
||||
pub const HOSTNAME_KEY: &str = "hostname";
|
||||
pub const DOMAINS_KEY: &str = "domains";
|
||||
pub const PATH_KEY: &str = "path";
|
||||
pub const REDIRECTS_KEY: &str = "redirects";
|
||||
|
||||
pub const NGINX_STAGING_CONFIG_PATH: &str = "/etc/librepages/nginx/sites-available/";
|
||||
pub const NGINX_PRODUCTION_CONFIG_PATH: &str = "/etc/librepages/nginx/sites-enabled/";
|
||||
|
||||
type MyResult<T> = std::result::Result<T, Box<dyn Error>>;
|
||||
|
||||
impl CreateSite {
|
||||
fn new(hostname: &str, path: &str, config: Option<libconfig::Config>) -> Self {
|
||||
let ctx = RefCell::new(context());
|
||||
ctx.borrow_mut().insert(HOSTNAME_KEY, hostname);
|
||||
ctx.borrow_mut().insert(PATH_KEY, path);
|
||||
if let Some(config) = config {
|
||||
ctx.borrow_mut().insert(REDIRECTS_KEY, &config.redirects);
|
||||
ctx.borrow_mut().insert(DOMAINS_KEY, &config.domains);
|
||||
}
|
||||
Self { ctx }
|
||||
}
|
||||
|
||||
fn render(&self) -> String {
|
||||
TEMPLATES
|
||||
.render(CREATE_SITE.name, &self.ctx.borrow())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use lazy_static::lazy_static;
|
||||
use rust_embed::RustEmbed;
|
||||
use tera::*;
|
||||
|
||||
pub const PAYLOAD_KEY: &str = "payload";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref TEMPLATES: Tera = {
|
||||
let mut tera = Tera::default();
|
||||
|
||||
for template in [crate::nginx::CREATE_SITE, crate::nginx::CREATE_SITE_FRAGMENT].iter() {
|
||||
template.register(&mut tera).expect(template.name);
|
||||
}
|
||||
// tera.autoescape_on(vec![".html", ".sql"]);
|
||||
tera
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "templates/"]
|
||||
pub struct Templates;
|
||||
|
||||
impl Templates {
|
||||
pub fn get_template(t: &TemplateFile) -> Option<String> {
|
||||
match Self::get(t.path) {
|
||||
Some(file) => Some(String::from_utf8_lossy(&file.data).into_owned()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context() -> Context {
|
||||
let mut ctx = Context::new();
|
||||
ctx
|
||||
}
|
||||
|
||||
pub struct TemplateFile {
|
||||
pub name: &'static str,
|
||||
pub path: &'static str,
|
||||
}
|
||||
|
||||
impl TemplateFile {
|
||||
pub const fn new(name: &'static str, path: &'static str) -> Self {
|
||||
Self { name, path }
|
||||
}
|
||||
|
||||
pub fn register(&self, t: &mut Tera) -> std::result::Result<(), tera::Error> {
|
||||
t.add_raw_template(self.name, &Templates::get_template(self).expect(self.name))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
pub fn register_from_file(&self, t: &mut Tera) -> std::result::Result<(), tera::Error> {
|
||||
use std::path::Path;
|
||||
t.add_template_file(Path::new("templates/").join(self.path), Some(self.name))
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
sudo certbot --nginx -d {{ hostname }}
|
|
@ -0,0 +1,29 @@
|
|||
server {
|
||||
# serve website on port 80
|
||||
listen [::]:80;
|
||||
listen 80;
|
||||
|
||||
# write error logs to file
|
||||
error_log /var/log/nginx/{{ hostname }}.error.log;
|
||||
# write access logs to file
|
||||
access_log /var/log/nginx/{{ hostname }}.access.log;
|
||||
|
||||
# serve only on this domain:
|
||||
server_name {{ hostname }};
|
||||
|
||||
# use files from this directory
|
||||
root {{ path }};
|
||||
|
||||
# remove .html from URL; it is cleaner this way
|
||||
rewrite ^(/.*)\.html(\?.*)?$ $1$2 permanent;
|
||||
|
||||
{% if redirects %}
|
||||
{% for redirect in redirects %}
|
||||
rewrite ^/{{redirect.from}}$ /{{ redirect.to }} redirect;
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
# when a request is received, try the index.html in the directory
|
||||
# or $uri.html
|
||||
try_files $uri/index.html $uri.html $uri/ $uri =404;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{% include "new_site_frag" %}
|
||||
|
||||
{% if domains %}
|
||||
{% for hostname in domains %}
|
||||
{% include "new_site_frag" %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
|
@ -38,8 +38,6 @@ DOCKER_IMG="realaravinth/$NAME:$3"
|
|||
|
||||
get_bin(){
|
||||
cp target/release/conductor $TARGET_DIR
|
||||
cp -r config/ $TARGET_DIR
|
||||
cp -r contrib/ $TARGET_DIR
|
||||
}
|
||||
|
||||
copy() {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
use actix_web::dev::ServiceRequest;
|
||||
use actix_web::web;
|
||||
use actix_web::Error;
|
||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||
use actix_web_httpauth::extractors::basic::BasicAuth;
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::AppCtx;
|
||||
|
@ -26,13 +26,14 @@ use crate::SETTINGS;
|
|||
pub mod meta;
|
||||
pub mod webhook;
|
||||
|
||||
pub async fn bearerauth(
|
||||
pub async fn httpauth(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
credentials: BasicAuth,
|
||||
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
|
||||
let _ctx: &AppCtx = req.app_data().unwrap();
|
||||
let token = credentials.token();
|
||||
if SETTINGS.authenticate(token) {
|
||||
let username = credentials.user_id();
|
||||
let password = credentials.password().unwrap();
|
||||
if SETTINGS.authenticate(username, password) {
|
||||
Ok(req)
|
||||
} else {
|
||||
let e = Error::from(ServiceError::Unauthorized);
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::errors::*;
|
|||
use crate::AppCtx;
|
||||
use crate::*;
|
||||
|
||||
use super::bearerauth;
|
||||
use super::httpauth;
|
||||
|
||||
pub mod routes {
|
||||
use super::*;
|
||||
|
@ -47,7 +47,7 @@ pub fn services(cfg: &mut web::ServiceConfig) {
|
|||
|
||||
#[actix_web_codegen_const_routes::post(
|
||||
path = "API_V1_ROUTES.webhook.post_event",
|
||||
wrap = "HttpAuthentication::bearer(bearerauth)"
|
||||
wrap = "HttpAuthentication::basic(httpauth)"
|
||||
)]
|
||||
async fn post_event(ctx: AppCtx, payload: web::Json<EventType>) -> ServiceResult<impl Responder> {
|
||||
ctx.conductor.process(payload.into_inner()).await;
|
||||
|
@ -71,7 +71,10 @@ pub mod tests {
|
|||
.await;
|
||||
|
||||
let creds = settings.creds.clone();
|
||||
let auth = format!("Bearer {}", creds.token,);
|
||||
let auth = format!(
|
||||
"Basic {}",
|
||||
base64::encode(format!("{}:{}", creds.username.clone(), creds.password))
|
||||
);
|
||||
|
||||
let msg = EventType::NewSite {
|
||||
hostname: "demo.librepages.org".into(),
|
||||
|
|
|
@ -19,7 +19,6 @@ use std::env;
|
|||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::JsonConfig;
|
||||
use actix_web::{error::InternalError, middleware, App, HttpServer};
|
||||
use actix_web_prom::PrometheusMetricsBuilder;
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::info;
|
||||
|
||||
|
@ -113,11 +112,6 @@ async fn serve(settings: Settings, ctx: AppCtx) -> std::io::Result<()> {
|
|||
let ip = settings.server.get_ip();
|
||||
println!("Starting server on: http://{ip}");
|
||||
|
||||
let prometheus = PrometheusMetricsBuilder::new("api")
|
||||
.endpoint("/metrics")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(middleware::Logger::default())
|
||||
|
@ -130,7 +124,6 @@ async fn serve(settings: Settings, ctx: AppCtx) -> std::io::Result<()> {
|
|||
middleware::TrailingSlash::Trim,
|
||||
))
|
||||
.app_data(get_json_err())
|
||||
.wrap(prometheus.clone())
|
||||
.configure(routes::services)
|
||||
})
|
||||
.bind(ip)?
|
||||
|
|
|
@ -54,7 +54,8 @@ pub enum ConductorType {
|
|||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Creds {
|
||||
pub token: String,
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
|
@ -68,15 +69,15 @@ pub struct Settings {
|
|||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Settings {
|
||||
pub fn authenticate(&self, token: &str) -> bool {
|
||||
self.creds.token == token
|
||||
pub fn authenticate(&self, username: &str, password: &str) -> bool {
|
||||
self.creds.username == username && self.creds.password == password
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self, ConfigError> {
|
||||
let mut s = Config::builder();
|
||||
|
||||
const CURRENT_DIR: &str = "./config/config.toml";
|
||||
const ETC: &str = "/etc/librepages/conductor/config.toml";
|
||||
const ETC: &str = "/etc/lpconductor/config.toml";
|
||||
|
||||
if let Ok(path) = env::var("LPCONDUCTOR_CONFIG") {
|
||||
s = s.add_source(File::with_name(&path));
|
||||
|
@ -137,13 +138,6 @@ fn set_separator_field(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<Defa
|
|||
&format!("{PREFIX}{SEPARATOR}SERVER{SEPARATOR}PROXY_HAS_TLS"),
|
||||
"server.proxy_has_tls",
|
||||
);
|
||||
|
||||
s = from_env(
|
||||
s,
|
||||
&format!("{PREFIX}{SEPARATOR}CREDS{SEPARATOR}TOKEN"),
|
||||
"creds.token",
|
||||
);
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
|
@ -154,13 +148,16 @@ mod tests {
|
|||
#[test]
|
||||
fn creds_works() {
|
||||
let settings = Settings::new().unwrap();
|
||||
let creds = settings.creds.clone();
|
||||
let mut creds = settings.creds.clone();
|
||||
|
||||
assert!(settings.authenticate(&creds.token));
|
||||
assert!(settings.authenticate(&creds.username, &creds.password));
|
||||
|
||||
creds.username = "noexist".into();
|
||||
assert!(!settings.authenticate(&creds.username, &creds.password));
|
||||
|
||||
let mut creds = settings.creds.clone();
|
||||
|
||||
creds.token = "noexist".into();
|
||||
assert!(!settings.authenticate(&creds.token))
|
||||
creds.password = "noexist".into();
|
||||
assert!(!settings.authenticate(&creds.username, &creds.password));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue