diff --git a/Cargo.lock b/Cargo.lock index 13647296..4805bce1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1457,7 +1457,7 @@ checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] name = "libmcaptcha" version = "0.1.4" -source = "git+https://github.com/mCaptcha/libmcaptcha?branch=master#6eac51de1035c20954752642b4fbdbf6ae3bec6d" +source = "git+https://github.com/mCaptcha/libmcaptcha?branch=master#1d4f97f511ad851a58359ecd1737b381b61cf22e" dependencies = [ "actix", "derive_builder", diff --git a/sqlx-data.json b/sqlx-data.json index 7e93ebf8..c8f0eb94 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -14,6 +14,32 @@ "nullable": [] } }, + "06699fda6b1542bf4544c0bdece91531a3020c24c9c76bcf967980e71ee25b42": { + "query": "SELECT email, secret FROM mcaptcha_users WHERE name = ($1)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "email", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "secret", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + true, + false + ] + } + }, "1be6274d5cc6d16f38285b8a62c9f66e8c3014cd403bc599598e911023bfeedb": { "query": "INSERT INTO mcaptcha_pow_fetched_stats \n (config_id) VALUES ((SELECT config_id FROM mcaptcha_config WHERE key = $1))", "describe": { diff --git a/src/api/v1/mcaptcha/levels.rs b/src/api/v1/mcaptcha/levels.rs index d5ec5906..53e8ab06 100644 --- a/src/api/v1/mcaptcha/levels.rs +++ b/src/api/v1/mcaptcha/levels.rs @@ -30,7 +30,6 @@ pub mod routes { pub struct Levels { pub add: &'static str, - pub delete: &'static str, pub get: &'static str, pub update: &'static str, } @@ -39,14 +38,8 @@ pub mod routes { pub const fn new() -> Levels { let add = "/api/v1/mcaptcha/add"; let update = "/api/v1/mcaptcha/update"; - let delete = "/api/v1/mcaptcha/delete"; let get = "/api/v1/mcaptcha/get"; - Levels { - add, - delete, - get, - update, - } + Levels { add, get, update } } } } diff --git a/src/pages/mod.rs b/src/pages/mod.rs index 46f9a6de..c70cd97f 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -11,8 +11,7 @@ * 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 . +* You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ use actix_web::web::ServiceConfig; @@ -51,17 +50,22 @@ mod tests { delete_user(NAME, &data).await; } - let (data, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await; + register_and_signin(NAME, EMAIL, PASSWORD).await; + let (data, _, signin_resp, token_key) = add_levels_util(NAME, PASSWORD).await; let cookies = get_cookie!(signin_resp); let app = get_app!(data).await; + let edit_sitekey_url = format!("/sitekey/{}/edit", &token_key.key); + let delete_sitekey_url = format!("/sitekey/{}/delete", &token_key.key); let urls = vec![ PAGES.home, PAGES.panel.sitekey.add, PAGES.panel.sitekey.list, PAGES.panel.notifications, - "/sitekey/test/delete", + PAGES.panel.settings, + &delete_sitekey_url, + &edit_sitekey_url, ]; for url in urls.iter() { diff --git a/src/pages/panel/mod.rs b/src/pages/panel/mod.rs index 2a74ecdb..5cdcdd71 100644 --- a/src/pages/panel/mod.rs +++ b/src/pages/panel/mod.rs @@ -1,25 +1,26 @@ /* -* 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 . -*/ + * 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 actix_identity::Identity; use actix_web::{HttpResponse, Responder}; use sailfish::TemplateOnce; mod notifications; +mod settings; pub mod sitekey; use crate::errors::PageResult; @@ -51,6 +52,7 @@ async fn panel(data: AppData, id: Identity) -> PageResult { pub fn services(cfg: &mut actix_web::web::ServiceConfig) { cfg.service(panel); + cfg.service(settings::settings); sitekey::services(cfg); cfg.service(notifications::notifications); } @@ -61,6 +63,7 @@ pub mod routes { pub home: &'static str, pub sitekey: Sitekey, pub notifications: &'static str, + pub settings: &'static str, } impl Panel { @@ -69,6 +72,7 @@ pub mod routes { home: "/", sitekey: Sitekey::new(), notifications: "/notifications", + settings: "/settings", } } } diff --git a/src/pages/panel/settings.rs b/src/pages/panel/settings.rs new file mode 100644 index 00000000..ba095721 --- /dev/null +++ b/src/pages/panel/settings.rs @@ -0,0 +1,49 @@ +/* + * 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 actix_identity::Identity; +use actix_web::{HttpResponse, Responder}; +use sailfish::TemplateOnce; + +use crate::errors::PageResult; +use crate::AppData; + +#[derive(TemplateOnce, Clone)] +#[template(path = "panel/settings/index.html")] +pub struct IndexPage { + email: Option, + secret: String, +} + +const PAGE: &str = "Settings"; + +#[my_codegen::get(path = "crate::PAGES.panel.settings", wrap = "crate::CheckLogin")] +pub async fn settings(data: AppData, id: Identity) -> PageResult { + let username = id.identity().unwrap(); + + let details = sqlx::query_as!( + IndexPage, + r#"SELECT email, secret FROM mcaptcha_users WHERE name = ($1)"#, + &username, + ) + .fetch_one(&data.db) + .await?; + + let body = details.render_once().unwrap(); + Ok(HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(body)) +} diff --git a/static/cache/img/svg/refresh.svg b/static/cache/img/svg/refresh.svg new file mode 100644 index 00000000..10cff0ec --- /dev/null +++ b/static/cache/img/svg/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/auth/login/index.html b/templates/auth/login/index.html index 01fcbd11..1513e5b1 100644 --- a/templates/auth/login/index.html +++ b/templates/auth/login/index.html @@ -34,7 +34,7 @@ id="password" required /> - <. include!("../../components/showPassword/index.html"); .> + <. include!("../../components/showPassword/index.html"); .> diff --git a/templates/components/clipboard/_copy.scss b/templates/components/clipboard/_copy.scss new file mode 100644 index 00000000..caa64a08 --- /dev/null +++ b/templates/components/clipboard/_copy.scss @@ -0,0 +1,38 @@ +/* + * 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 . + */ + +@mixin copy-icon-base { + margin: auto; + padding: 5px; +} + +@mixin copy-icon { + @include copy-icon-base; +} + +@mixin copy-icon-hover { + cursor: pointer; + filter: invert(17%) sepia(93%) saturate(5039%) hue-rotate(204deg) + brightness(100%) contrast(98%); +} + +@mixin copy-done-icon { + @include copy-icon-base; + display: none; + filter: invert(58%) sepia(60%) saturate(331%) hue-rotate(76deg) + brightness(91%) contrast(92%); +} diff --git a/templates/components/clipboard/index.html b/templates/components/clipboard/index.html new file mode 100644 index 00000000..3e415565 --- /dev/null +++ b/templates/components/clipboard/index.html @@ -0,0 +1,10 @@ +" + alt="<.= COPY_ALT .>" + data-<.= clipboard_data.0 .>="<.= clipboard_data.1 .>" +/> +" + alt="<.= DONE_ALT .>" +/> diff --git a/templates/components/clipboard/index.ts b/templates/components/clipboard/index.ts new file mode 100644 index 00000000..31844109 --- /dev/null +++ b/templates/components/clipboard/index.ts @@ -0,0 +1,65 @@ +/* + * 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 . + */ + +class CopyIcon { + copyIconClass: string; + copyDoneIconClass: string; + writeText: string; + + constructor( + writeText: string, + copyIconClass: string, + copyDoneIconClass: string, + ) { + this.copyIconClass = copyIconClass; + this.copyDoneIconClass = copyDoneIconClass; + this.writeText = writeText; + + this.__registerHandlers(); + } + + __registerHandlers() { + const icons = document.querySelectorAll(`.${this.copyIconClass}`); + icons.forEach(icon => { + icon.addEventListener('click', e => this.copySitekey(e)); + }); + } + + /* + * Copy secret to clipboard + */ + async copySitekey(e: Event) { + const image = e.target; + if (!image.classList.contains(this.copyIconClass)) { + throw new Error( + 'This method should only be called when sitekey copy button/icon is clicked', + ); + } + const copyDoneIcon = ( + image.parentElement.querySelector(`.${this.copyDoneIconClass}`) + ); + await navigator.clipboard.writeText(this.writeText); + image.style.display = 'none'; + copyDoneIcon.style.display = 'block'; + setTimeout(() => { + copyDoneIcon.style.display = 'none'; + image.style.display = 'block'; + }, 1200); + } +} + +export default CopyIcon; diff --git a/templates/components/footers.html b/templates/components/footers.html index 809fc286..27daf514 100644 --- a/templates/components/footers.html +++ b/templates/components/footers.html @@ -10,7 +10,7 @@ diff --git a/templates/components/showPassword/index.ts b/templates/components/showPassword/index.ts index 04562f2e..0f3b21a0 100644 --- a/templates/components/showPassword/index.ts +++ b/templates/components/showPassword/index.ts @@ -50,8 +50,7 @@ const hidePasswordButtons = () => { // e is click event from show password container export const showPassword = () => { - const form = document.querySelector('form'); - const inputs = form.querySelectorAll('input'); + const inputs = document.body.querySelectorAll('input'); if (display == 'hidden') { display = 'show'; @@ -93,13 +92,3 @@ export const registerShowPassword = () => { }; export default registerShowPassword; - -/* - * so here's what im going to do: - * the wrapper will be a check box and the check box will manipulate - * show password and hide password buttons using CSS. - * - * There will also be an event hadler attached that will change field types of - * parent fields only. Well, sibling maybe. Will have to see document structure - * - */ diff --git a/templates/index.ts b/templates/index.ts index 0e30fc70..220facba 100644 --- a/templates/index.ts +++ b/templates/index.ts @@ -20,6 +20,7 @@ import {Router} from './router'; import * as login from './auth/login/ts/'; import * as register from './auth/register/ts/'; import * as panel from './panel/ts/index'; +import settings from './panel/settings/'; import * as addSiteKey from './panel/sitekey/add/ts'; import * as editSitekey from './panel/sitekey/edit/'; import * as deleteSitekey from './panel/sitekey/delete/'; @@ -37,6 +38,7 @@ import './components/error/main.scss'; import './components/showPassword/main.scss'; import './panel/css/main.scss'; import './panel/navbar/main.scss'; +import './panel/settings/main.scss'; import './panel/notifications/main.scss'; import './panel/header/taskbar/main.scss'; import './panel/help-banner/main.scss'; @@ -50,6 +52,7 @@ log.setMode(MODE.production); const router = new Router(); router.register(VIEWS.panelHome, panel.index); +router.register(VIEWS.settings, settings); router.register(VIEWS.registerUser, register.index); router.register(VIEWS.loginUser, login.index); router.register(VIEWS.notifications, notidications.index); diff --git a/templates/panel/index.html b/templates/panel/index.html index 1e363d31..65bd0f2e 100644 --- a/templates/panel/index.html +++ b/templates/panel/index.html @@ -1,3 +1,8 @@ +<. const DONE_ALT: &str = "sitekey copied"; .> +<. const DONE_CLASS: &str = "sitekey__copy-done-icon"; .> +<. const COPY_ALT: &str = "copy sitekey"; .> +<. const COPY_CLASS: &str = "sitekey__copy-icon"; .> + <. include!("../components/headers/index.html"); .> <. include!("./navbar/index.html"); .>
@@ -37,12 +42,8 @@ include!("./navbar/index.html"); .>
- " - alt="copy sitekey" data-sitekey="<.= sitekey.key .>" /> " - alt="sitekey copied" data-sitekey="<.= sitekey.key .>" /> + <. let clipboard_data = ("sitekey", &sitekey.key); .> + <. include!("../components/clipboard/index.html"); .>
  • - + " alt="" />
    Settings diff --git a/templates/panel/settings/index.html b/templates/panel/settings/index.html new file mode 100644 index 00000000..7d32af8a --- /dev/null +++ b/templates/panel/settings/index.html @@ -0,0 +1,56 @@ +<. const COPY_ALT: &str = "copy secret"; .> +<. const COPY_CLASS: &str = "settings__secret-copy"; .> +<. const DONE_ALT: &str = "secret copied"; .> +<. const DONE_CLASS: &str = "settings__secret-copy-done"; .> + +<. let clipboard_data = ("secret", &secret); .> + +<. include!("../../components/headers/index.html"); .> +<. include!("../navbar/index.html"); .> +
    +<. include!("../header/index.html"); .> +
    + <. include!("../help-banner/index.html"); .> + + + +<. include!("../../components/footers.html"); .> diff --git a/templates/panel/settings/index.ts b/templates/panel/settings/index.ts new file mode 100644 index 00000000..870ad342 --- /dev/null +++ b/templates/panel/settings/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 . + */ + +import registerShowPassword from '../../components/showPassword/'; +import CopyIcon from '../../components/clipboard/'; + +const SECRET_COPY_ICON = 'settings__secret-copy'; +const SECRET_COPY_DONE_ICON = 'settings__secret-copy-done'; + +const index = () => { + registerShowPassword(); + + const secretElement = ( + document.querySelector(`.${SECRET_COPY_ICON}`) + ); + const writeText = secretElement.dataset.secret; + new CopyIcon(writeText, SECRET_COPY_ICON, SECRET_COPY_DONE_ICON); +}; + +export default index; diff --git a/templates/panel/settings/main.scss b/templates/panel/settings/main.scss new file mode 100644 index 00000000..ccdd2e38 --- /dev/null +++ b/templates/panel/settings/main.scss @@ -0,0 +1,30 @@ +/* + * 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 '../../components/clipboard/copy'; + +.settings__secret-copy { + @include copy-icon; +} + +.settings__secret-copy:hover .settings__secret-copy-done:hover { + @include copy-icon-hover; +} + +.settings__secret-copy-done { + @include copy-done-icon; +} diff --git a/templates/panel/sitekey/list/css/main.scss b/templates/panel/sitekey/list/css/main.scss index 7150a454..ad168b17 100644 --- a/templates/panel/sitekey/list/css/main.scss +++ b/templates/panel/sitekey/list/css/main.scss @@ -18,6 +18,7 @@ @import '../../../../reset'; @import '../../../../vars'; @import '../../../../components/box'; +@import '../../../../components/clipboard/copy'; @import '../../../../components/table/main'; .sitekey__table { @@ -37,26 +38,17 @@ width: 10px; } -@mixin copy-icon-base { - margin: auto; - padding: 5px; -} - .sitekey__copy-icon { - @include copy-icon-base; + @include copy-icon; } -.sitekey__copy-icon:hover { - cursor: pointer; - filter: invert(17%) sepia(93%) saturate(5039%) hue-rotate(204deg) - brightness(100%) contrast(98%); +.sitekey__copy-icon:hover, +.sitekey__copy-done-icon:hover { + @include copy-icon-hover; } .sitekey__copy-done-icon { - @include copy-icon-base; - display: none; - filter: invert(58%) sepia(60%) saturate(331%) hue-rotate(76deg) - brightness(91%) contrast(92%); + @include copy-done-icon; } .sitekey__key-container { diff --git a/templates/panel/sitekey/list/index.html b/templates/panel/sitekey/list/index.html index 215204af..a677a5b0 100644 --- a/templates/panel/sitekey/list/index.html +++ b/templates/panel/sitekey/list/index.html @@ -1,3 +1,8 @@ +<. const DONE_ALT: &str = "sitekey copied"; .> +<. const DONE_CLASS: &str = "sitekey__copy-done-icon"; .> +<. const COPY_ALT: &str = "copy sitekey"; .> +<. const COPY_CLASS: &str = "sitekey__copy-icon"; .> + <. include!("../../../components/headers/index.html"); .> <. include!("../../navbar/index.html"); .>
    @@ -28,12 +33,8 @@ include!("../../navbar/index.html"); .>
    - " - alt="copy sitekey" data-sitekey="<.= sitekey.key .>" /> " - alt="sitekey copied" data-sitekey="<.= sitekey.key .>" /> + <. let clipboard_data = ("sitekey", &sitekey.key); .> + <. include!("../../../components/clipboard/index.html"); .>
    -
    - <. let key = format!("/sitekey/{}", &sitekey.key); .> - <. include!("../view/__edit-sitekey-icon.html"); .> -
    +
    + <. let key = format!("/sitekey/{}", &sitekey.key); .> + <. include!("../view/__edit-sitekey-icon.html"); .> +
    <. } .> diff --git a/templates/panel/sitekey/list/ts/index.ts b/templates/panel/sitekey/list/ts/index.ts index 78ccc1bc..8eca0c9f 100644 --- a/templates/panel/sitekey/list/ts/index.ts +++ b/templates/panel/sitekey/list/ts/index.ts @@ -14,40 +14,19 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - -export const index = () => { - registerCopySitekey(); -}; +import CopyIcon from '../../../../components/clipboard/'; const SITEKEY_COPY_ICON = `sitekey__copy-icon`; const SITEKEY_COPY_DONE_ICON = `sitekey__copy-done-icon`; -const registerCopySitekey = () => { - const icons = document.querySelectorAll(`.${SITEKEY_COPY_ICON}`); - icons.forEach(icon => { - icon.addEventListener('click', e => copySitekey(e)); - }); -}; - -/* - * Copy sitekey to clipboard - */ -const copySitekey = async (e: Event) => { - const image = e.target; +export const index = () => { + const image = document.querySelector(`.${SITEKEY_COPY_ICON}`); if (!image.classList.contains(SITEKEY_COPY_ICON)) { throw new Error( 'This method should only be called when sitekey copy button/icon is clicked', ); } - const copyDoneIcon = ( - image.parentElement.querySelector(`.${SITEKEY_COPY_DONE_ICON}`) - ); const sitekey = image.dataset.sitekey; - await navigator.clipboard.writeText(sitekey); - image.style.display = 'none'; - copyDoneIcon.style.display = 'block'; - setTimeout(() => { - copyDoneIcon.style.display = 'none'; - image.style.display = 'block'; - }, 1200); + + new CopyIcon(sitekey, SITEKEY_COPY_ICON, SITEKEY_COPY_DONE_ICON); }; diff --git a/templates/views/v1/routes.ts b/templates/views/v1/routes.ts index c513493d..4bf51ad0 100644 --- a/templates/views/v1/routes.ts +++ b/templates/views/v1/routes.ts @@ -20,6 +20,7 @@ const ROUTES = { loginUser: '/login/', signoutUser: '/api/v1/signout', panelHome: '/', + settings: '/settings/', docsHome: '/docs/', notifications: '/notifications', listSitekey: '/sitekeys/',