Kreu aŭtentigo kaj rajtigo

Ĉi tiuj modjuloj aŭtentigas uzanton kaj provas la rajtojn de la uzanto.
This commit is contained in:
Savanni D'Gerinel 2021-12-30 00:05:35 -05:00
parent 113ddbcd42
commit e48ed1f2dd
7 changed files with 239 additions and 255 deletions

208
Cargo.lock generated
View File

@ -2,42 +2,12 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
dependencies = [
"byteorder",
"safemem",
]
[[package]]
name = "base64"
version = "0.13.0"
@ -81,47 +51,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cc"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"time",
"winapi",
]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "common"
version = "0.1.0"
@ -149,12 +84,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "fnv"
version = "1.0.7"
@ -241,7 +170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check 0.9.3",
"version_check",
]
[[package]]
@ -297,7 +226,7 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855"
dependencies = [
"base64 0.13.0",
"base64",
"bitflags",
"bytes",
"headers-core",
@ -422,42 +351,18 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "jsonwebtoken"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d438ea707d465c230305963b67f8357a1d56fcfad9434797d7cb1c46c2e41df"
dependencies = [
"base64 0.9.3",
"chrono",
"ring",
"serde",
"serde_derive",
"serde_json",
"untrusted",
]
[[package]]
name = "kampanja-kontrolada-servilo"
version = "0.1.0"
dependencies = [
"orizentic",
"tokio",
"uuid",
"warp",
]
@ -473,12 +378,6 @@ version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.5"
@ -574,25 +473,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
@ -615,23 +495,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "orizentic"
version = "1.0.1"
dependencies = [
"chrono",
"clap",
"itertools",
"jsonwebtoken",
"serde",
"serde_derive",
"serde_json",
"thiserror",
"uuid",
"version_check 0.1.5",
"yaml-rust",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -824,18 +687,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "ring"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
dependencies = [
"cc",
"lazy_static",
"libc",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.5"
@ -944,12 +795,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.77"
@ -975,15 +820,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.29"
@ -1137,7 +973,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24"
dependencies = [
"base64 0.13.0",
"base64",
"byteorder",
"bytes",
"http",
@ -1171,7 +1007,7 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check 0.9.3",
"version_check",
]
[[package]]
@ -1189,24 +1025,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "untrusted"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
[[package]]
name = "url"
version = "2.2.2"
@ -1232,21 +1056,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom 0.2.3",
"serde",
]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "version_check"
version = "0.9.3"
@ -1325,12 +1136,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

1
aŭtentigo.db Normal file
View File

@ -0,0 +1 @@
[{"jti":"fa613049-e370-4576-b3f0-b7757c3e0cca","aud":"savanni","exp":1672379098,"iss":"savanni","iat":1640843098,"sub":"admin","perms":["admin"]}]

View File

@ -6,6 +6,6 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
orizentic = { path = "../../orizentic/" }
tokio = { version = "1", features = ["full"] }
uuid = { version = "0.8.2", features = ["v4"] }
warp = { version = "0.3.1" }

100
servilo/src/aŭtentigo.rs Normal file
View File

@ -0,0 +1,100 @@
use std::{
collections::HashMap,
convert::Infallible,
str::FromStr,
sync::{Arc, RwLock},
};
use uuid::{adapter::Hyphenated, Uuid};
use warp::{reject, reject::Reject, Filter, Rejection};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Ĵetono(String);
impl From<&str> for Ĵetono {
fn from(s: &str) -> Self {
Ĵetono(s.to_owned())
}
}
impl FromStr for Ĵetono {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Ĵetono(s.to_owned()))
}
}
impl From<Ĵetono> for String {
fn from(s: Ĵetono) -> Self {
s.0.clone()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Uzantnomo(String);
impl From<&str> for Uzantnomo {
fn from(s: &str) -> Self {
Uzantnomo(s.to_owned())
}
}
impl From<Uzantnomo> for String {
fn from(s: Uzantnomo) -> Self {
s.0.clone()
}
}
pub trait AŭtentigoDB: Clone + Send + Sync {
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<Uzantnomo>;
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono;
}
#[derive(Clone)]
pub struct MemAŭtentigo {
mem: HashMap<Ĵetono, Uzantnomo>,
}
impl MemAŭtentigo {
pub fn new() -> Self {
Self {
mem: HashMap::new(),
}
}
}
impl AŭtentigoDB for MemAŭtentigo {
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<Uzantnomo> {
self.mem.get(&ĵetono).cloned()
}
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono {
let ĵetono = Ĵetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
self.mem.insert(ĵetono.clone(), uzantnomo);
ĵetono
}
}
#[derive(Debug)]
pub struct AŭtentigoPostulas;
impl Reject for AŭtentigoPostulas {}
pub fn kun_aŭtentigo(
auth_ctx: Arc<RwLock<impl AŭtentigoDB>>,
) -> impl Filter<Extract = (Uzantnomo,), Error = Rejection> + Clone {
let auth_ctx = auth_ctx.clone();
warp::header("authentication").and_then({
let auth_ctx = auth_ctx.clone();
move |text| {
let auth_ctx = auth_ctx.clone();
async move {
match auth_ctx.read().unwrap().aŭtentigu(text) {
Some(uzantnomo) => Ok(uzantnomo),
None => Err(reject::custom(AŭtentigoPostulas)),
}
}
}
})
}

View File

@ -1,68 +1,79 @@
use orizentic::{OrizenticCtx, Secret, Username};
use std::convert::Infallible;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::{Arc, RwLock};
use warp::{reject, Filter, Rejection};
use warp::{Filter, Rejection};
fn with_auth(
auth_ctx: Arc<RwLock<OrizenticCtx>>,
) -> impl Filter<Extract = (Username,), Error = Rejection> + Clone {
let auth_ctx = auth_ctx.clone();
warp::header("authentication").and_then({
let auth_ctx = auth_ctx.clone();
move |text| {
let auth_ctx = auth_ctx.clone();
async move {
match auth_ctx.read().unwrap().decode_and_validate_text(text) {
Ok(token) => Ok(token.claims.audience),
Err(_) => Err(reject()),
}
}
}
})
#[path = "aŭtentigo.rs"]
mod aŭtentigo;
use aŭtentigo::{kun_aŭtentigo, AŭtentigoDB, AŭtentigoPostulas, MemAŭtentigo, Uzantnomo};
use crate::rajtigo::{MemRajtigo, Rajtigo, Rajto};
mod rajtigo;
async fn traktilo_de_listigu_ludantojn(
uzantnomo: Uzantnomo,
rajtigo: Arc<RwLock<impl Rajtigo>>,
) -> Result<impl warp::Reply, Rejection> {
if rajtigo.read().unwrap().havas_rajton(uzantnomo, |rajtoj| {
rajtoj.fold(false, |acc, r| acc || *r == Rajto::from("admin"))
}) {
Ok(warp::reply::json(&vec!["Alice", "Betty", "Charles"]))
} else {
Err(warp::reject::not_found())
}
}
fn gm_routes(
auth_ctx: Arc<RwLock<OrizenticCtx>>,
) -> impl Filter<Extract = (), Error = Rejection> + Clone {
let base_route = with_auth(auth_ctx).and(warp::path("gm"));
async fn traktilu_erarojn(err: Rejection) -> Result<impl warp::Reply, Infallible> {
let kodo;
let mesaĝo;
if let Some(_) = err.find::<AŭtentigoPostulas>() {
kodo = warp::http::StatusCode::UNAUTHORIZED;
mesaĝo = "Ensalutu";
} else {
kodo = warp::http::StatusCode::INTERNAL_SERVER_ERROR;
mesaĝo = "Netraktita mesaĝo";
}
let character_sheet = {
let auth_ctx = auth_ctx.clone();
with_auth(auth_ctx)
.and(warp::path!("gm" / "character" / String))
.map(|auth: Username, name| format!("name: {} {}", String::from(auth), name))
};
Ok(warp::reply::with_status(
warp::reply::json(&mesaĝo.to_owned()),
kodo,
))
}
#[tokio::main]
pub async fn main() {
let auth_ctx = Arc::new(RwLock::new(OrizenticCtx::new(
Secret(Vec::from("abcdefg".as_bytes())),
vec![],
)));
let auth_ctx = Arc::new(RwLock::new(MemAŭtentigo::new()));
let ĵetono = auth_ctx
.write()
.unwrap()
.kreu_ĵetono(Uzantnomo::from("Savanni"));
println!("ĵetono: {}", String::from(ĵetono));
let rajtigo = Arc::new(RwLock::new(MemRajtigo::new()));
rajtigo.write().unwrap().aldonu_rajtoj(
Uzantnomo::from("Savanni"),
&mut (vec![Rajto::from("admin")].into_iter()),
);
let send_item = {
let listigu_ludantojn = {
let auth_ctx = auth_ctx.clone();
with_auth(auth_ctx)
.and(warp::path!("gm" / "send_item"))
.map(|auth: Username| format!("send_item: {}", String::from(auth)))
kun_aŭtentigo(auth_ctx)
.and(warp::path!("api" / "ludantoj"))
.and_then({
let rajtigo = rajtigo.clone();
move |uzantnomo| {
let rajtigo = rajtigo.clone();
traktilo_de_listigu_ludantojn(uzantnomo, rajtigo)
}
})
};
let send_resource = warp::header("authentication")
.and(warp::path!("gm" / "send_resource"))
.map(|auth: String| format!("send_resource"));
let pc_sheet = warp::header("authentication")
.and(warp::path!("player" / "character" / String))
.map(|authentication: String, name: String| format!("name: {}", name));
let filter = character_sheet.or(send_item).or(send_resource).or(pc_sheet);
let filter = listigu_ludantojn.recover(traktilu_erarojn);
let server = warp::serve(filter);
server
.run(SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
8000,
8001,
))
.await;
}

74
servilo/src/rajtigo.rs Normal file
View File

@ -0,0 +1,74 @@
use crate::aŭtentigo::Uzantnomo;
use std::collections::{HashMap, HashSet};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Rajto(String);
impl From<&str> for Rajto {
fn from(s: &str) -> Self {
Rajto(s.to_owned())
}
}
impl From<Rajto> for String {
fn from(s: Rajto) -> Self {
s.0.clone()
}
}
pub trait Rajtigo {
fn havas_rajton<'a, F>(&'a self, uzantnomo: Uzantnomo, provo: F) -> bool
where
F: FnOnce(&mut (dyn Iterator<Item = &'a Rajto> + 'a)) -> bool;
fn rajtoj(&self, uzantnomo: &Uzantnomo) -> Vec<Rajto>;
fn aldonu_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>));
fn foriru_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>));
fn foriru_uzanto(&mut self, uzantnomo: Uzantnomo);
}
pub struct MemRajtigo {
rajtoj: HashMap<Uzantnomo, HashSet<Rajto>>,
}
impl MemRajtigo {
pub fn new() -> Self {
MemRajtigo {
rajtoj: HashMap::new(),
}
}
}
impl Rajtigo for MemRajtigo {
fn havas_rajton<'a, F>(&'a self, uzantnomo: Uzantnomo, provo: F) -> bool
where
F: FnOnce(&mut (dyn Iterator<Item = &'a Rajto> + 'a)) -> bool,
{
match self.rajtoj.get(&uzantnomo) {
Some(rajtoj) => provo(&mut rajtoj.iter()),
None => false,
}
}
fn rajtoj(&self, uzantnomo: &Uzantnomo) -> Vec<Rajto> {
self.rajtoj
.get(&uzantnomo)
.map(|r| r.into_iter().cloned().collect::<Vec<Rajto>>())
.unwrap_or(vec![])
}
fn aldonu_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>)) {
let valoro = self.rajtoj.entry(uzantnomo).or_insert(HashSet::new());
while let Some(r) = rajtoj.next() {
valoro.insert(r);
}
}
fn foriru_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>)) {
let valoro = self.rajtoj.entry(uzantnomo).or_insert(HashSet::new());
while let Some(r) = rajtoj.next() {
valoro.remove(&r);
}
}
fn foriru_uzanto(&mut self, uzantnomo: Uzantnomo) {
let _ = self.rajtoj.remove(&uzantnomo);
}
}

View File

@ -10,17 +10,13 @@ in pkgs.mkShell {
name = "kampanja-kontrolado";
nativeBuildInputs = [
pkgs.gnome.webkitgtk
pkgs.glib
pkgs.gtk3
pkgs.libpng
pkgs.nodejs
pkgs.openssl
pkgs.pkg-config
pkgs.wrapGAppsHook
rust
unstable.rust-analyzer
pkgs.nodejs
pkgs.hugo
];
shellHook = ''