From db941d51b7284dff091a9b59c90997173c598f4e Mon Sep 17 00:00:00 2001 From: realaravinth Date: Tue, 20 Jul 2021 15:22:15 +0530 Subject: [PATCH] delete captcha option and sudo page --- src/pages/auth/mod.rs | 1 + src/pages/auth/sudo.rs | 85 +++++++++++++++++++ src/pages/panel/sitekey/delete.rs | 30 +++---- static/cache/img/svg/trash.svg | 1 + templates/auth/login/ts/index.ts | 18 ++-- templates/auth/sudo/getForm.test.ts | 31 +++++++ .../sitekey/delete => auth/sudo}/index.html | 11 +-- templates/auth/sudo/index.ts | 34 ++++++++ .../additional-data/getAdditionalData.test.ts | 33 +++++++ .../components/additional-data/index.html | 3 + templates/components/additional-data/index.ts | 36 ++++++++ templates/components/details-footer/main.scss | 5 ++ templates/components/footers.html | 2 +- templates/index.ts | 2 + templates/panel/sitekey/delete/index.ts | 51 +++++++++++ templates/panel/sitekey/view/__form-top.html | 10 ++- templates/views/v1/routes.ts | 1 + 17 files changed, 320 insertions(+), 34 deletions(-) create mode 100644 src/pages/auth/sudo.rs create mode 100644 static/cache/img/svg/trash.svg create mode 100644 templates/auth/sudo/getForm.test.ts rename templates/{panel/sitekey/delete => auth/sudo}/index.html (64%) create mode 100644 templates/auth/sudo/index.ts create mode 100644 templates/components/additional-data/getAdditionalData.test.ts create mode 100644 templates/components/additional-data/index.html create mode 100644 templates/components/additional-data/index.ts create mode 100644 templates/panel/sitekey/delete/index.ts diff --git a/src/pages/auth/mod.rs b/src/pages/auth/mod.rs index fa7bb602..e276d3ec 100644 --- a/src/pages/auth/mod.rs +++ b/src/pages/auth/mod.rs @@ -17,6 +17,7 @@ pub mod login; pub mod register; +pub mod sudo; pub fn services(cfg: &mut actix_web::web::ServiceConfig) { cfg.service(login::login); diff --git a/src/pages/auth/sudo.rs b/src/pages/auth/sudo.rs new file mode 100644 index 00000000..7d81e2d0 --- /dev/null +++ b/src/pages/auth/sudo.rs @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +use std::fmt::Display; + +use sailfish::TemplateOnce; + +#[derive(Clone, TemplateOnce)] +#[template(path = "auth/sudo/index.html")] +pub struct SudoPage<'a> { + url: &'a str, + data: Option, +} + +pub const PAGE: &str = "Confirm Access"; + +impl<'a> SudoPage<'a> { + //pub fn new(url: &'a str, data: Option>) -> Self { + pub fn new(url: &'a str, data: Option>) -> Self + where + K: Display, + V: Display, + { + let data = if let Some(data) = data { + if !data.is_empty() { + let mut s = String::new(); + for (k, v) in data.iter() { + s.push_str(&format!(" data-{}={}", k, v)); + } + Some(s) + } else { + None + } + } else { + None + }; + + Self { url, data } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sudo_page_works() { + let data = vec![ + ("firefox", "mozilla"), + ("chrome", "google"), + ("servo", "mozilla"), + ]; + assert!(SudoPage::new::("foo", None).data.is_none()); + + let sudo = SudoPage::new("foo", Some(data.clone())); + + data.iter().for_each(|(k, v)| { + assert!( + sudo.data.as_ref().unwrap().contains(k) + && sudo.data.as_ref().unwrap().contains(v) + ) + }); + + let data_str = " data-firefox=mozilla data-chrome=google data-servo=mozilla"; + assert_eq!(sudo.data.as_ref().unwrap(), data_str); + + assert!(SudoPage::new::("foo", Some(Vec::default())) + .data + .is_none()); + } +} diff --git a/src/pages/panel/sitekey/delete.rs b/src/pages/panel/sitekey/delete.rs index 0159b212..7f7fa7c4 100644 --- a/src/pages/panel/sitekey/delete.rs +++ b/src/pages/panel/sitekey/delete.rs @@ -15,31 +15,21 @@ * along with this program. If not, see . */ -use actix_web::{HttpResponse, Responder}; -use lazy_static::lazy_static; +use actix_web::{web, HttpResponse, Responder}; use my_codegen::get; use sailfish::TemplateOnce; -use crate::PAGES; - -#[derive(Clone, TemplateOnce)] -#[template(path = "panel/sitekey/delete/index.html")] -struct IndexPage; -const PAGE: &str = "Confirm Access"; - -impl Default for IndexPage { - fn default() -> Self { - IndexPage - } -} - -lazy_static! { - static ref INDEX: String = IndexPage::default().render_once().unwrap(); -} +use crate::pages::auth::sudo::SudoPage; +use crate::{PAGES, V1_API_ROUTES}; #[get(path = "PAGES.panel.sitekey.delete", wrap = "crate::CheckLogin")] -pub async fn delete_sitekey() -> impl Responder { +pub async fn delete_sitekey(path: web::Path) -> impl Responder { + let key = path.into_inner(); + let data = vec![("sitekey", key)]; + let page = SudoPage::new(V1_API_ROUTES.mcaptcha.delete, Some(data)) + .render_once() + .unwrap(); HttpResponse::Ok() .content_type("text/html; charset=utf-8") - .body(&*INDEX) + .body(&page) } diff --git a/static/cache/img/svg/trash.svg b/static/cache/img/svg/trash.svg new file mode 100644 index 00000000..f24d55bf --- /dev/null +++ b/static/cache/img/svg/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/auth/login/ts/index.ts b/templates/auth/login/ts/index.ts index 38d18bca..964d0a87 100644 --- a/templates/auth/login/ts/index.ts +++ b/templates/auth/login/ts/index.ts @@ -25,6 +25,16 @@ import createError from '../../../components/error/index'; //import '../forms.scss'; +export const getPassword = () => { + const passwordElement = document.getElementById('password'); + if (passwordElement === null) { + console.debug('Password is null'); + return; + } + + return passwordElement.value; +}; + const login = async (e: Event) => { e.preventDefault(); const loginElement = document.getElementById('login'); @@ -36,13 +46,7 @@ const login = async (e: Event) => { const login = loginElement.value; isBlankString(login, 'username', e); - const passwordElement = document.getElementById('password'); - if (passwordElement === null) { - console.debug('Password is null'); - return; - } - - const password = passwordElement.value; + const password = getPassword(); const payload = { login, diff --git a/templates/auth/sudo/getForm.test.ts b/templates/auth/sudo/getForm.test.ts new file mode 100644 index 00000000..a49a5ea8 --- /dev/null +++ b/templates/auth/sudo/getForm.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +import form from './index'; + +it('sudo form works', () => { + try { + form(); + } catch (e) { + expect(e.message).toBe("Couldn't form element, is the component loaded?"); + } + + const element = document.createElement('form'); + element.id = 'form'; + document.body.appendChild(element); + expect(form()).toBe(element); +}); diff --git a/templates/panel/sitekey/delete/index.html b/templates/auth/sudo/index.html similarity index 64% rename from templates/panel/sitekey/delete/index.html rename to templates/auth/sudo/index.html index 3d09ede0..4dbe796e 100644 --- a/templates/panel/sitekey/delete/index.html +++ b/templates/auth/sudo/index.html @@ -1,12 +1,12 @@ -<. include!("../../../components/headers/index.html"); .> +<. include!("../../components/headers/index.html"); .>
- <. include!("../../../auth/logo.html"); .> + <. include!("../logo.html"); .>

@@ -21,9 +21,10 @@ id="password" required /> - <. include!("../../../components/showPassword/index.html"); .> + <. include!("../../components/showPassword/index.html"); .>

-<. include!("../../../components/footers.html"); .> +<. include!("../../components/additional-data/index.html"); .> +<. include!("../../components/footers.html"); .> diff --git a/templates/auth/sudo/index.ts b/templates/auth/sudo/index.ts new file mode 100644 index 00000000..bff7a0af --- /dev/null +++ b/templates/auth/sudo/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +const form = () => { + let element = null; + const ID = 'form'; + + if (element === null) { + element = document.getElementById(ID); + if (element === undefined) { + throw new Error("Couldn't form element, is the component loaded?"); + } else { + return element; + } + } else { + element; + } +}; + +export default form; diff --git a/templates/components/additional-data/getAdditionalData.test.ts b/templates/components/additional-data/getAdditionalData.test.ts new file mode 100644 index 00000000..7bece21e --- /dev/null +++ b/templates/components/additional-data/getAdditionalData.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +import additionalData from './index'; + +it('sudo form works', () => { + try { + additionalData(); + } catch (e) { + expect(e.message).toBe( + "Couldn't retrieve additional data element, is the component loaded?", + ); + } + + const element = document.createElement('div'); + element.id = 'additional-data'; + document.body.appendChild(element); + expect(additionalData()).toBe(element); +}); diff --git a/templates/components/additional-data/index.html b/templates/components/additional-data/index.html new file mode 100644 index 00000000..eda10e56 --- /dev/null +++ b/templates/components/additional-data/index.html @@ -0,0 +1,3 @@ +<. if data.is_some() && !data.as_ref().unwrap().is_empty() { .> +
>
+<. } .> diff --git a/templates/components/additional-data/index.ts b/templates/components/additional-data/index.ts new file mode 100644 index 00000000..84aad12d --- /dev/null +++ b/templates/components/additional-data/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +const additionalData = () => { + let element = null; + const ID = 'additional-data'; + + if (element === null) { + element = document.getElementById(ID); + if (element === undefined) { + throw new Error( + "Couldn't retrieve additional data element, is the component loaded?", + ); + } else { + return element; + } + } else { + element; + } +}; + +export default additionalData; diff --git a/templates/components/details-footer/main.scss b/templates/components/details-footer/main.scss index b9a1d7ef..817c2e66 100644 --- a/templates/components/details-footer/main.scss +++ b/templates/components/details-footer/main.scss @@ -50,3 +50,8 @@ $footer-font-size: 14px; .details__link { color: $blue-link; } + +.sitekey-form__delete { + filter: invert(12%) sepia(70%) saturate(6818%) hue-rotate(341deg) + brightness(82%) contrast(111%); +} diff --git a/templates/components/footers.html b/templates/components/footers.html index 8afd2d74..809fc286 100644 --- a/templates/components/footers.html +++ b/templates/components/footers.html @@ -10,7 +10,7 @@ diff --git a/templates/index.ts b/templates/index.ts index d277fe8c..0e30fc70 100644 --- a/templates/index.ts +++ b/templates/index.ts @@ -22,6 +22,7 @@ import * as register from './auth/register/ts/'; import * as panel from './panel/ts/index'; import * as addSiteKey from './panel/sitekey/add/ts'; import * as editSitekey from './panel/sitekey/edit/'; +import * as deleteSitekey from './panel/sitekey/delete/'; import * as listSitekeys from './panel/sitekey/list/ts'; import * as notidications from './panel/notifications/ts'; import {MODE} from './logger'; @@ -55,6 +56,7 @@ router.register(VIEWS.notifications, notidications.index); router.register(VIEWS.listSitekey, listSitekeys.index); router.register(VIEWS.addSiteKey, addSiteKey.index); router.register(VIEWS.editSitekey('[A-Z),a-z,0-9]+'), editSitekey.index); +router.register(VIEWS.deleteSitekey('[A-Z),a-z,0-9]+'), deleteSitekey.index); try { router.route(); diff --git a/templates/panel/sitekey/delete/index.ts b/templates/panel/sitekey/delete/index.ts new file mode 100644 index 00000000..47808be8 --- /dev/null +++ b/templates/panel/sitekey/delete/index.ts @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * 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 . + */ + +import {getPassword} from '../../../auth/login/ts/'; +import form from '../../../auth/sudo/'; +import additionalData from '../../../components/additional-data'; + +import getFormUrl from '../../../utils/getFormUrl'; +import genJsonPayload from '../../../utils/genJsonPayload'; +import createError from '../../../components/error'; + +import VIEWS from '../../../views/v1/routes'; + +const submit = async (e: Event) => { + e.preventDefault(); + const password = getPassword(); + const key = additionalData().dataset.sitekey; + + const payload = { + password, + key, + }; + + const formUrl = getFormUrl(form()); + + const res = await fetch(formUrl, genJsonPayload(payload)); + if (res.ok) { + window.location.assign(VIEWS.listSitekey); + } else { + const err = await res.json(); + createError(err.error); + } +}; + +export const index = () => { + form().addEventListener('submit', submit, true); +}; diff --git a/templates/panel/sitekey/view/__form-top.html b/templates/panel/sitekey/view/__form-top.html index 466ced91..0c7aa79a 100644 --- a/templates/panel/sitekey/view/__form-top.html +++ b/templates/panel/sitekey/view/__form-top.html @@ -21,8 +21,16 @@ <. if READONLY { .> <. let key = "."; .> - <. include!("./__edit-sitekey-icon.html"); .> + <. include!("./__edit-sitekey-icon.html"); .> + + <. } else { .> + <. } .> + " + alt="Delete sitekey" + /> +