diff --git a/Cargo.lock b/Cargo.lock index 69ebb6fa..f0ecedf1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1588,6 +1588,7 @@ dependencies = [ "log", "mime", "mime_guess", + "openssl", "pow_sha256", "pretty_env_logger", "rand 0.8.4", @@ -1873,6 +1874,15 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +[[package]] +name = "openssl-src" +version = "111.15.0+1.1.1k" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.65" @@ -1882,6 +1892,7 @@ dependencies = [ "autocfg", "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] diff --git a/Cargo.toml b/Cargo.toml index e292ad3a..96e5e2a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,8 @@ lettre = { version = "0.10.0-rc.3", features = [ "smtp-transport" ]} +openssl = { version = "0.10.29", features = ["vendored"] } + [build-dependencies] serde_yaml = "0.8.17" diff --git a/src/pages/panel/sitekey/mod.rs b/src/pages/panel/sitekey/mod.rs index f4cf6d85..66748801 100644 --- a/src/pages/panel/sitekey/mod.rs +++ b/src/pages/panel/sitekey/mod.rs @@ -29,8 +29,8 @@ pub mod routes { impl Sitekey { pub const fn new() -> Self { Sitekey { - list: "/sitekey/list", - add: "/sitekey/add", + list: "/sitekeys", + add: "/sitekeys/add", view: "/sitekey/{key}", } } diff --git a/static/cache/img/svg/clipboard.svg b/static/cache/img/svg/clipboard.svg new file mode 100644 index 00000000..ccee454d --- /dev/null +++ b/static/cache/img/svg/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/cache/img/svg/external-link.svg b/static/cache/img/svg/external-link.svg new file mode 100644 index 00000000..6236df3e --- /dev/null +++ b/static/cache/img/svg/external-link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/components/_button.scss b/templates/components/_button.scss index cbb8510a..2d3a1a09 100644 --- a/templates/components/_button.scss +++ b/templates/components/_button.scss @@ -17,7 +17,7 @@ @mixin violet-button-hover { background-color: $light-violet; - cursor: grab; + cursor: pointer; transform: translateY(-5px); } diff --git a/templates/components/error/main.scss b/templates/components/error/main.scss index 92e032f1..a4acfb82 100644 --- a/templates/components/error/main.scss +++ b/templates/components/error/main.scss @@ -45,7 +45,7 @@ $message-bg: #d63f3f; } .err__close:hover { - cursor: grab; + cursor: pointer; width: 20px; height: 20px; } diff --git a/templates/components/table/main.scss b/templates/components/table/main.scss new file mode 100644 index 00000000..1142a956 --- /dev/null +++ b/templates/components/table/main.scss @@ -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 '../../vars'; + +@mixin table { + background-color: $white; + width: 90%; + padding: 0 10px; +} + +@mixin table__title-text { + font-size: 1rem; + padding: 0.75rem 0.5rem; + box-sizing: border-box; + text-align: left; + width: 100%; + border-bottom: 0.1px solid $light-grey; +} diff --git a/templates/email/css/button.css b/templates/email/css/button.css index 2b514cbe..955931f1 100644 --- a/templates/email/css/button.css +++ b/templates/email/css/button.css @@ -1,6 +1,6 @@ .button:hover { background-color: #993299; - cursor: grab; + cursor: pointer; transform: translateY(-5px); } diff --git a/templates/index.ts b/templates/index.ts index 58f60339..33c6b3d2 100644 --- a/templates/index.ts +++ b/templates/index.ts @@ -21,6 +21,7 @@ import * as login from './auth/login/ts/'; import * as register from './auth/register/ts/'; import * as panel from './panel/ts/index'; import * as addSiteKey from './panel/sitekey/add/ts'; +import * as listSitekeys from './panel/sitekey/list/ts'; import {MODE} from './logger'; import log from './logger'; @@ -48,6 +49,7 @@ const router = new Router(); router.register(VIEWS.panelHome, panel.index); router.register(VIEWS.registerUser, register.index); router.register(VIEWS.loginUser, login.index); +router.register(VIEWS.listSitekey, listSitekeys.index); router.register(VIEWS.addSiteKey, addSiteKey.index); try { diff --git a/templates/mobile.ts b/templates/mobile.ts index 5af6fd56..b0b10e53 100644 --- a/templates/mobile.ts +++ b/templates/mobile.ts @@ -23,3 +23,4 @@ import './panel/header/taskbar/mobile.scss'; import './panel/navbar/mobile.scss'; import './panel/help-banner/mobile.scss'; import './panel/sitekey/add/css/mobile.scss'; +import './panel/sitekey/list/css/mobile.scss'; diff --git a/templates/panel/header/taskbar/index.html b/templates/panel/header/taskbar/index.html index 420002be..c7458988 100644 --- a/templates/panel/header/taskbar/index.html +++ b/templates/panel/header/taskbar/index.html @@ -4,29 +4,31 @@ -->
  • - - + +
  • " alt="Profile" /> + crate::FILES.get("./static/cache/img/svg/moon.svg").unwrap() .>" + alt="Profile" />
  • - - " - alt="Notifications" /> - + + " + alt="Notifications" /> +
  • - - " alt="Profile" - /> + + " + alt="Profile" />
  • diff --git a/templates/panel/header/taskbar/main.scss b/templates/panel/header/taskbar/main.scss index 98f86f18..31270513 100644 --- a/templates/panel/header/taskbar/main.scss +++ b/templates/panel/header/taskbar/main.scss @@ -48,10 +48,9 @@ } .taskbar__icon:hover { - cursor: grab; + cursor: pointer; background-color: $light-grey; color: $green; - background-color: $light-grey; filter: invert(58%) sepia(60%) saturate(331%) hue-rotate(76deg) brightness(91%) contrast(92%); } diff --git a/templates/panel/index.html b/templates/panel/index.html index 83e0ca50..707b9bb9 100644 --- a/templates/panel/index.html +++ b/templates/panel/index.html @@ -1,40 +1,63 @@ -<. include!("../components/headers/index.html"); .> -<. include!("./navbar/index.html"); .> +<. include!("../components/headers/index.html"); .> <. +include!("./navbar/index.html"); .>
    -<. include!("./header/index.html"); .> -
    - <. include!("./help-banner/index.html"); .> -
    - + <. include!("./header/index.html"); .> +
    + <. include!("./help-banner/index.html"); .> +
    <. if sitekeys.is_empty() { .> -
      -

      - It looks like you don't have any sitekeys. Click - here to add new sitekey. +

        +

        + It looks like you don't have any sitekeys. Click + here to add new + sitekey.

        -
      - +
    <.} else {.> - + + + + + + + + <. for sitekey in sitekeys.iter() { .> + + + + + <. } .> + +
    + Your Sitekeys +
    + + <.= sitekey.name .> + + +
    + " + alt="copy sitekey" data-sitekey="<.= sitekey.key .>" /> " + alt="sitekey copied" data-sitekey="<.= sitekey.key .>" /> + + <.= &sitekey.key[0..5] .> + +
    +
    <.}.> - -
    -<. include!("../components/footers.html"); .> +
    + <. include!("../components/footers.html"); .> +
    +
    diff --git a/templates/panel/navbar/main.scss b/templates/panel/navbar/main.scss index d371f2e0..09c39ffa 100644 --- a/templates/panel/navbar/main.scss +++ b/templates/panel/navbar/main.scss @@ -57,7 +57,7 @@ } .secondary-menu__heading:hover { color: $green; - cursor: grab; + cursor: pointer; } .secondary-menu__logo { @@ -99,7 +99,7 @@ .secondary-menu__item-link:hover { color: $green; - cursor: grab; + cursor: pointer; filter: invert(58%) sepia(60%) saturate(331%) hue-rotate(76deg) brightness(91%) contrast(92%); } diff --git a/templates/panel/navbar/mobile.scss b/templates/panel/navbar/mobile.scss index 84109d58..66138ca2 100644 --- a/templates/panel/navbar/mobile.scss +++ b/templates/panel/navbar/mobile.scss @@ -34,7 +34,7 @@ } .nav__hamburger-menu:hover { - cursor: grab; + cursor: pointer; } .nav__hamburger-menu:hover > span { @@ -75,5 +75,5 @@ .secondary-menu__brand-name:hover { color: $light-text; - cursor: grab; + cursor: pointer; } diff --git a/templates/panel/notifications/main.scss b/templates/panel/notifications/main.scss index a6c4faec..88c62b44 100644 --- a/templates/panel/notifications/main.scss +++ b/templates/panel/notifications/main.scss @@ -16,20 +16,15 @@ */ @import '../../vars'; +@import '../../components//table/main'; .notification__table { - background-color: $white; - width: 90%; - padding: 0 10px; + @include table; + margin: auto; } .notification__title-text { - font-size: 1rem; - padding: 0.75rem 0.5rem; - box-sizing: border-box; - text-align: left; - width: 100%; - border-bottom: 0.1px solid $light-grey; + @include table__title-text; } .notification__mark-read-btn { @@ -45,7 +40,7 @@ } .notification-data__container { - font-size: 0.7rem; + font-size: 0.7rem; } .notification__mark-read { diff --git a/templates/panel/sitekey/add/ts/form/index.ts b/templates/panel/sitekey/add/ts/form/index.ts index b2fa2736..5dc9e1af 100644 --- a/templates/panel/sitekey/add/ts/form/index.ts +++ b/templates/panel/sitekey/add/ts/form/index.ts @@ -56,7 +56,7 @@ const submit = async (e: Event) => { const res = await fetch(formUrl, genJsonPayload(payload)); if (res.ok) { const data = await res.json(); - window.location.assign(VIEWS.listSitekey(data.key)); + window.location.assign(VIEWS.viewSitekey(data.key)); } else { const err = await res.json(); createError(err.error); diff --git a/templates/panel/sitekey/list/css/main.scss b/templates/panel/sitekey/list/css/main.scss index 0ef0636e..8f51a660 100644 --- a/templates/panel/sitekey/list/css/main.scss +++ b/templates/panel/sitekey/list/css/main.scss @@ -18,38 +18,87 @@ @import '../../../../reset'; @import '../../../../vars'; @import '../../../../components/box'; +@import '../../../../components/table/main'; -.sitekey-list__box { - @include box; - padding-bottom: 0px; +.sitekey__table { + @include table; + margin: auto; } -.sitekey-list__title { - @include box-title; -} - -.sitekey-list__item-container { - display: block; - width: 100%; - box-sizing: border-box; - border-bottom: 0.1px solid $light-grey; - padding: 20px; - color: $black-text; -} - -.sitekey-list__item { - display: flex; - width: 100%; -} - -.sitekey-list__item-container:hover { - background-color: $light-grey; +.sitekey__table-title-text { + @include table__title-text; } .sitekey-list__name { - flex: 3; + min-width: 450px; } .sitekey-list__key { - flex: 1; + width: 10px; +} + +@mixin copy-icon-base { + margin: auto; + padding: 5px; +} + +.sitekey__copy-icon { + @include copy-icon-base; +} + +.sitekey__copy-icon:hover { + cursor: pointer; + filter: invert(17%) sepia(93%) saturate(5039%) hue-rotate(204deg) + brightness(100%) contrast(98%); +} + +.sitekey__copy-done-icon { + @include copy-icon-base; + display: none; + filter: invert(58%) sepia(60%) saturate(331%) hue-rotate(76deg) + brightness(91%) contrast(92%); +} + +.sitekey__key-container { + border-radius: 10px; + background: $backdrop; + margin: 2px; + padding: 5px; + display: flex; + max-width: 150px; + border: 0.1px solid rgba(0, 0, 0, 0.125); +} + +.sitekey__widget-link { + border-left: 0.1px solid $light-grey; + margin: 5; + margin: auto; + padding-left: 20px; + height: 100%; + padding-right: 15px; +} + +.sitekey-list__sitekey-link { + display: inline-block; + width: 100%; + text-decoration: none; + color: $blue-link; + padding: 20px; +} + +.sitekey-list__sitekey-link:visited { + color: $blue-link; +} + +.sitekey-list__sitekey-link:hover { + background-color: $light-grey; + cursor: pointer; +} + +.sitekey__widget-link { + color: $blue-link; +} + +.sitekey__widget-link:visited { + color: $blue-link; } diff --git a/templates/panel/sitekey/list/css/mobile.scss b/templates/panel/sitekey/list/css/mobile.scss new file mode 100644 index 00000000..f035c3cf --- /dev/null +++ b/templates/panel/sitekey/list/css/mobile.scss @@ -0,0 +1,20 @@ +/* + * 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 . + */ + +.sitekey-list__name { + min-width: 120px; +} diff --git a/templates/panel/sitekey/list/index.html b/templates/panel/sitekey/list/index.html index 260b7002..20b9e758 100644 --- a/templates/panel/sitekey/list/index.html +++ b/templates/panel/sitekey/list/index.html @@ -1,23 +1,53 @@ -<. include!("../../../components/headers/index.html"); .> -<. include!("../../navbar/index.html"); .> +<. include!("../../../components/headers/index.html"); .> <. +include!("../../navbar/index.html"); .>
    -<. include!("../../header/index.html"); .> -
    - <.include!("../../help-banner/index.html"); .> - -
    - - -
    - -<. include!("../../../components/footers.html"); .> + <. include!("../../header/index.html"); .> +
    + <.include!("../../help-banner/index.html"); .> + +
    + + + + + + + + + <. for sitekey in sitekeys.iter() { .> + + + + + <. } .> + +
    + Your Sitekeys +
    + + <.= sitekey.name .> + + +
    + " + alt="copy sitekey" data-sitekey="<.= sitekey.key .>" /> " + alt="sitekey copied" data-sitekey="<.= sitekey.key .>" /> + + <.= &sitekey.key[0..5] .> + +
    +
    +
    + + <. include!("../../../components/footers.html"); .> +
    +
    diff --git a/templates/panel/sitekey/list/ts/index.ts b/templates/panel/sitekey/list/ts/index.ts index 661a4391..78ccc1bc 100644 --- a/templates/panel/sitekey/list/ts/index.ts +++ b/templates/panel/sitekey/list/ts/index.ts @@ -15,4 +15,39 @@ * along with this program. If not, see . */ -export const index = () => {}; +export const index = () => { + registerCopySitekey(); +}; + +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; + 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); +}; diff --git a/templates/panel/sitekey/view/index.html b/templates/panel/sitekey/view/index.html index 0cb71888..7311f17d 100644 --- a/templates/panel/sitekey/view/index.html +++ b/templates/panel/sitekey/view/index.html @@ -8,47 +8,51 @@
    -
    -

    Sitekey: <.= name .> - Click here to see CAPTCHA widget in action -

    - - - - - <. for (count, level) in levels.iter().enumerate() { .> - <. include!("./existing-level.html"); .> - <. } .> - -
    +
    +

    Sitekey: <.= name .> + View widget + " + alt="View widget deployment" + /> + +

    + + + <. for (count, level) in levels.iter().enumerate() { .> + <. include!("./existing-level.html"); .> + <. } .> +
    <. include!("../../../components/footers.html"); .> diff --git a/templates/panel/ts/index.ts b/templates/panel/ts/index.ts index d8398ff8..7263718e 100644 --- a/templates/panel/ts/index.ts +++ b/templates/panel/ts/index.ts @@ -15,72 +15,8 @@ * along with this program. If not, see . */ +import * as listSitekeys from '../sitekey/list/ts/'; + export const index = () => { - // const html = document.documentElement; - // const body = document.body; - // const menuLinks = document.querySelectorAll('.admin-menu a'); - // const collapseBtn = document.querySelector('.admin-menu .collapse-btn'); - // const toggleMobileMenu = document.querySelector('.toggle-mob-menu'); - // const switchInput = document.querySelector('.switch input'); - // const switchLabel = document.querySelector('.switch label'); - // const switchLabelText = switchLabel.querySelector('span:last-child'); - // const collapsedClass = 'collapsed'; - // const lightModeClass = 'light-mode'; - // - // /*TOGGLE HEADER STATE*/ - // collapseBtn.addEventListener('click', function() { - // body.classList.toggle(collapsedClass); - // this.getAttribute('aria-expanded') == 'true' - // ? this.setAttribute('aria-expanded', 'false') - // : this.setAttribute('aria-expanded', 'true'); - // this.getAttribute('aria-label') == 'collapse menu' - // ? this.setAttribute('aria-label', 'expand menu') - // : this.setAttribute('aria-label', 'collapse menu'); - // }); - // - // /*TOGGLE MOBILE MENU*/ - // toggleMobileMenu.addEventListener('click', function() { - // body.classList.toggle('mob-menu-opened'); - // this.getAttribute('aria-expanded') == 'true' - // ? this.setAttribute('aria-expanded', 'false') - // : this.setAttribute('aria-expanded', 'true'); - // this.getAttribute('aria-label') == 'open menu' - // ? this.setAttribute('aria-label', 'close menu') - // : this.setAttribute('aria-label', 'open menu'); - // }); - // - // /*SHOW TOOLTIP ON MENU LINK HOVER*/ - // for (const link of menuLinks) { - // link.addEventListener('mouseenter', function() { - // if ( - // body.classList.contains(collapsedClass) && - // window.matchMedia('(min-width: 768px)').matches - // ) { - // const tooltip = this.querySelector('span').textContent; - // this.setAttribute('title', tooltip); - // } else { - // this.removeAttribute('title'); - // } - // }); - // } - // - // /*TOGGLE LIGHT/DARK MODE*/ - // if (localStorage.getItem('dark-mode') === 'false') { - // html.classList.add(lightModeClass); - // switchInput.checked = false; - // switchLabelText.textContent = 'Light'; - // } - // - // switchInput.addEventListener('input', function() { - // html.classList.toggle(lightModeClass); - // if (html.classList.contains(lightModeClass)) { - // switchLabelText.textContent = 'Light'; - // localStorage.setItem('dark-mode', 'false'); - // } else { - // switchLabelText.textContent = 'Dark'; - // localStorage.setItem('dark-mode', 'true'); - // } - // }); - // -// let a; + listSitekeys.index(); }; diff --git a/templates/views/v1/routes.ts b/templates/views/v1/routes.ts index 8746dc61..799cb116 100644 --- a/templates/views/v1/routes.ts +++ b/templates/views/v1/routes.ts @@ -21,8 +21,9 @@ const ROUTES = { signoutUser: '/api/v1/signout', panelHome: '/', docsHome: '/docs/', - listSitekey: (key: string) => `/sitekey/${key}/`, - addSiteKey: '/sitekey/add', + listSitekey: '/sitekeys/', + viewSitekey: (key: string) => `/sitekey/${key}/`, + addSiteKey: '/sitekeys/add', }; export default ROUTES;